<commit_before>package org.nutz.lang.util;

import java.io.File;
import java.io.FileFilter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.LinkedList;

import org.nutz.lang.Encoding;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;

/**
 * 磁盘操作的帮助函数集合
 * 
 * @author zozoh(<EMAIL>)
 * @author bonyfish(<EMAIL>)
 */
public abstract class Disks {

	/**
	 * 一个 Vistor 模式的目录深层遍历
	 * 
	 * @param f
	 *            要遍历的目录或者文件，如果是目录，深层遍历，否则，只访问一次文件
	 * @param fv
	 *            对文件要进行的操作
	 * @param filter
	 *            遍历目录时，哪些文件应该被忽略
	 * @return 遍历的文件个数
	 */
	public static int visitFile(File f, FileVisitor fv, FileFilter filter) {
		int re = 0;
		if (f.isFile()) {
			fv.visit(f);
			re++;
		} else if (f.isDirectory()) {
			File[] fs = null == filter ? f.listFiles() : f.listFiles(filter);
			for (File theFile : fs)
				re += visitFile(theFile, fv, filter);
		}
		return re;
	}

	/**
	 * 将两个文件对象比较，得出相对路径
	 * 
	 * @param base
	 *            基础文件对象
	 * @param file
	 *            相对文件对象
	 * @return 相对于基础文件对象的相对路径
	 */
	public static String getRelativePath(File base, File file) {
		return getRelativePath(base.getAbsolutePath(), file.getAbsolutePath());
	}

	/**
	 * 将两个路径比较，得出相对路径
	 * 
	 * @param base
	 *            基础路径
	 * @param path
	 *            相对文件路径
	 * @return 相对于基础路径对象的相对路径
	 */
	public static String getRelativePath(String base, String path) {
		String[] bb = Strings.splitIgnoreBlank(getCanonicalPath(base), "[\\\\/]");
		String[] ff = Strings.splitIgnoreBlank(getCanonicalPath(path), "[\\\\/]");
		int len = Math.min(bb.length, ff.length);
		int pos = 0;
		for (; pos < len; pos++)
			if (!bb[pos].equals(ff[pos]))
				break;
		StringBuilder sb = new StringBuilder(Strings.dup("../", bb.length - 1 - pos));
		return sb.append(Lang.concat(pos, ff.length - pos, '/', ff)).toString();
	}

	/**
	 * 整理路径。 将会合并路径中的 ".."
	 * 
	 * @param path
	 *            路径
	 * @return 整理后的路径
	 */
	public static String getCanonicalPath(String path) {
		String[] pa = Strings.splitIgnoreBlank(path, "[\\\\/]");
		LinkedList<String> paths = new LinkedList<String>();
		for (String s : pa) {
			if ("..".equals(s)) {
				if (paths.size() > 0)
					paths.removeLast();
				continue;
			} else {
				paths.add(s);
			}
		}
		return Lang.concat("/", paths).toString();
	}

	/**
	 * @return 当前账户的主目录全路径
	 */
	public static String home() {
		return System.getProperty("user.home");
	}<commit_msg>修复LocalResourceScan 在 Linux 下的严重问题<commit_after>package org.nutz.lang.util;

import java.io.File;
import java.io.FileFilter;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.LinkedList;

import org.nutz.lang.Encoding;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;

/**
 * 磁盘操作的帮助函数集合
 * 
 * @author zozoh(<EMAIL>)
 * @author bonyfish(<EMAIL>)
 */
public abstract class Disks {

	/**
	 * 一个 Vistor 模式的目录深层遍历
	 * 
	 * @param f
	 *            要遍历的目录或者文件，如果是目录，深层遍历，否则，只访问一次文件
	 * @param fv
	 *            对文件要进行的操作
	 * @param filter
	 *            遍历目录时，哪些文件应该被忽略
	 * @return 遍历的文件个数
	 */
	public static int visitFile(File f, FileVisitor fv, FileFilter filter) {
		int re = 0;
		if (f.isFile()) {
			fv.visit(f);
			re++;
		} else if (f.isDirectory()) {
			File[] fs = null == filter ? f.listFiles() : f.listFiles(filter);
			for (File theFile : fs)
				re += visitFile(theFile, fv, filter);
		}
		return re;
	}

	/**
	 * 将两个文件对象比较，得出相对路径
	 * 
	 * @param base
	 *            基础文件对象
	 * @param file
	 *            相对文件对象
	 * @return 相对于基础文件对象的相对路径
	 */
	public static String getRelativePath(File base, File file) {
		return getRelativePath(base.getAbsolutePath(), file.getAbsolutePath());
	}

	/**
	 * 将两个路径比较，得出相对路径
	 * 
	 * @param base
	 *            基础路径
	 * @param path
	 *            相对文件路径
	 * @return 相对于基础路径对象的相对路径
	 */
	public static String getRelativePath(String base, String path) {
		String[] bb = Strings.splitIgnoreBlank(getCanonicalPath(base), "[\\\\/]");
		String[] ff = Strings.splitIgnoreBlank(getCanonicalPath(path), "[\\\\/]");
		int len = Math.min(bb.length, ff.length);
		int pos = 0;
		for (; pos < len; pos++)
			if (!bb[pos].equals(ff[pos]))
				break;
		StringBuilder sb = new StringBuilder(Strings.dup("../", bb.length - 1 - pos));
		return sb.append(Lang.concat(pos, ff.length - pos, '/', ff)).toString();
	}

	/**
	 * 整理路径。 将会合并路径中的 ".."
	 * 
	 * @param path
	 *            路径
	 * @return 整理后的路径
	 */
	public static String getCanonicalPath(String path) {
		if (Strings.isBlank(path))
			return path;
		String[] pa = Strings.splitIgnoreBlank(path, "[\\\\/]");
		LinkedList<String> paths = new LinkedList<String>();
		for (String s : pa) {
			if ("..".equals(s)) {
				if (paths.size() > 0)
					paths.removeLast();
				continue;
			} else {
				paths.add(s);
			}
		}
		if (path.charAt(0) == '/')
			return Lang.concat("/", paths).insert(0, '/').toString();
		return Lang.concat("/", paths).toString();
	}

	/**
	 * @return 当前账户的主目录全路径
	 */
	public static String home() {
		return System.getProperty("user.home");
	}
{'fraction_non_alphanumeric': 0.16191962543893873, 'fraction_numerical': 0.0019508388607101053, 'mean_word_length': 2.837574850299401, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5088330', 'n_tokens_mistral': 2250, 'n_tokens_neox': 2110, 'n_words': 393}