files - Analyzing a Path

本文通过实战演示了Java NIO中Files类的静态方法使用,这些方法用于操作文件、目录和其他类型的文件。展示了如何检查文件的存在性、是否为目录、是否可执行等属性,并获取文件大小、所有者、最后修改时间等信息。

Final class java.nio.file.Files consists exclusively of static methods that operate on files, directories, or other types of files.

In most cases, the methods defined here will delegate to the associated file system provider to perform the file operations.

// files/PathAnalysis.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.

import java.io.IOException;
import java.nio.file.*;

public class PathAnalysis {
  static void say(String id, Object result) {
    System.out.print(id + ": ");
    System.out.println(result);
  }

  public static void main(String[] args) throws IOException {
    System.out.println(System.getProperty("os.name"));
    Path p = Paths.get("PathAnalysis.java").toAbsolutePath();
    say("Exists", Files.exists(p));
    say("Directory", Files.isDirectory(p));
    say("Executable", Files.isExecutable(p));
    say("Readable", Files.isReadable(p));
    say("RegularFile", Files.isRegularFile(p));
    say("Writable", Files.isWritable(p));
    say("notExists", Files.notExists(p));
    say("Hidden", Files.isHidden(p));
    say("size", Files.size(p));
    say("FileStore", Files.getFileStore(p));
    say("LastModified: ", Files.getLastModifiedTime(p));
    say("Owner", Files.getOwner(p));
    say("ContentType", Files.probeContentType(p));
    say("SymbolicLink", Files.isSymbolicLink(p));
    if (Files.isSymbolicLink(p)) say("SymbolicLink", Files.readSymbolicLink(p));
    if (FileSystems.getDefault().supportedFileAttributeViews().contains("posix")) {
      say("PosixFilePermissions", Files.getPosixFilePermissions(p));
    }
  }
}
/* My Output:
Mac OS X
Exists: true
Directory: false
Executable: false
Readable: true
RegularFile: true
Writable: true
notExists: false
Hidden: false
size: 1714
FileStore: / (/dev/disk1s1)
LastModified: : 2019-04-15T15:40:43Z
Owner: wangbingfeng
ContentType: null
SymbolicLink: false

PosixFilePermissions: [OWNER_READ, OWNER_WRITE, OTHERS_READ, GROUP_READ]
*/
public static String probeContentType(Path path)
                               throws IOException

Probes the content type of a file.

This method uses the installed FileTypeDetector implementations to probe the given file to determine its content type. Each file type detector's probeContentType is invoked, in turn, to probe the file type. If the file is recognized then the content type is returned. If the file is not recognized by any of the installed file type detectors then a system-default file type detector is invoked to guess the content type.

A given invocation of the Java virtual machine maintains a system-wide list of file type detectors. Installed file type detectors are loaded using the service-provider loading facility defined by the ServiceLoader class. Installed file type detectors are loaded using the system class loader. If the system class loader cannot be found then the extension class loader is used; If the extension class loader cannot be found then the bootstrap class loader is used. File type detectors are typically installed by placing them in a JAR file on the application class path or in the extension directory, the JAR file contains a provider-configuration file named java.nio.file.spi.FileTypeDetector in the resource directory META-INF/services, and the file lists one or more fully-qualified names of concrete subclass of FileTypeDetector that have a zero argument constructor. If the process of locating or instantiating the installed file type detectors fails then an unspecified error is thrown. The ordering that installed providers are located is implementation specific.

The return value of this method is the string form of the value of a Multipurpose Internet Mail Extension (MIME) content type as defined by RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies. The string is guaranteed to be parsable according to the grammar in the RFC.

Parameters:

path - the path to the file to probe

Returns:

The content type of the file, or null if the content type cannot be determined

Throws:

IOException - if an I/O error occurs

SecurityException - If a security manager is installed and it denies an unspecified permission required by a file type detector implementation.

references:

1. On Java 8 - Bruce Eckel

2. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/files/PathAnalysis.java

3. https://docs.oracle.com/javase/8/docs/api/java/nio/file/spi/FileTypeDetector.html

const path = require("path"); const fs = require("fs"); const glob = require("fast-glob"); const esbuild = require("esbuild"); const vue = require("esbuild-plugin-vue3"); const yargs = require("yargs"); const cliui = require("cliui")(); const chalk = require("chalk"); const html_plugin = require("./frappe-html"); const vue_style_plugin = require("./frappe-vue-style"); const rtlcss = require("rtlcss"); const postCssPlugin = require("@frappe/esbuild-plugin-postcss2").default; const ignore_assets = require("./ignore-assets"); const sass_options = require("./sass_options"); const build_cleanup_plugin = require("./build-cleanup"); const { app_list, assets_path, apps_path, sites_path, get_public_path, log, log_warn, log_error, bench_path, get_redis_subscriber, } = require("./utils"); const argv = yargs .usage("Usage: node esbuild [options]") .option("apps", { type: "string", description: "Run build for specific apps", }) .option("skip_frappe", { type: "boolean", description: "Skip building frappe assets", }) .option("files", { type: "string", description: "Run build for specified bundles", }) .option("watch", { type: "boolean", description: "Run in watch mode and rebuild on file changes", }) .option("live-reload", { type: "boolean", description: `Automatically reload Desk when assets are rebuilt. Can only be used with the --watch flag.`, }) .option("production", { type: "boolean", description: "Run build in production mode", }) .option("run-build-command", { type: "boolean", description: "Run build command for apps", }) .option("save-metafiles", { type: "boolean", description: "Saves esbuild metafiles for built assets. Useful for analyzing bundle size. More info: https://esbuild.github.io/api/#metafile", }) .option("using-cached", { type: "boolean", description: "Skips build and uses cached build artifacts to update assets.json (used by Bench)", }) .example("node esbuild --apps frappe,erpnext", "Run build only for frappe and erpnext") .example( "node esbuild --files frappe/website.bundle.js,frappe/desk.bundle.js", "Run build only for specified bundles" ) .version(false).argv; const APPS = (!argv.apps ? app_list : argv.apps.split(",")).filter( (app) => !(argv.skip_frappe && app == "frappe") ); const FILES_TO_BUILD = argv.files ? argv.files.split(",") : []; let WATCH_MODE = Boolean(argv.watch); // 生产模式强制禁用 watch const WATCH_MODE = PRODUCTION ? false : Boolean(argv.watch); // 生产模式才允许运行构建命令 const RUN_BUILD_COMMAND = !WATCH_MODE && PRODUCTION && Boolean(argv["run-build-command"]); const TOTAL_BUILD_TIME = `${chalk.black.bgGreen(" DONE ")} Total Build Time`; const NODE_PATHS = [].concat( // node_modules of apps directly importable app_list.map((app) => path.resolve(apps_path, app, "node_modules")).filter(fs.existsSync), // import js file of any app if you provide the full path app_list.map((app) => path.resolve(apps_path, app)).filter(fs.existsSync) ); const USING_CACHED = Boolean(argv["using-cached"]); execute().catch((e) => { console.error(e); process.exit(1); }); if (WATCH_MODE) { // listen for open files in editor event open_in_editor(); } async function execute() { console.time(TOTAL_BUILD_TIME); if (USING_CACHED) { await update_assets_json_from_built_assets(APPS); await update_assets_json_in_cache(); console.timeEnd(TOTAL_BUILD_TIME); process.exit(0); } let results; try { results = await build_assets_for_apps(APPS, FILES_TO_BUILD); } catch (e) { log_error("There were some problems during build"); log(); log(chalk.dim(e.stack)); if (process.env.CI || PRODUCTION) { process.kill(process.pid); } return; } if (!WATCH_MODE) { log_built_assets(results); console.timeEnd(TOTAL_BUILD_TIME); log(); } else { log("Watching for changes..."); } for (const result of results) { await write_assets_json(result.metafile); } RUN_BUILD_COMMAND && run_build_command_for_apps(APPS); if (!WATCH_MODE) { process.exit(0); } } async function update_assets_json_from_built_assets(apps) { const assets = await get_assets_json_path_and_obj(false); const assets_rtl = await get_assets_json_path_and_obj(true); for (const app of apps) { await update_assets_obj(app, assets.obj, assets_rtl.obj); } for (const { obj, path } of [assets, assets_rtl]) { const data = JSON.stringify(obj, null, 4); await fs.promises.writeFile(path, data); } } async function update_assets_obj(app, assets, assets_rtl) { const app_path = path.join(apps_path, app, app); const dist_path = path.join(app_path, "public", "dist"); const files = await glob("**/*.bundle.*.{js,css}", { cwd: dist_path }); const assets_dist = path.join("assets", app, "dist"); const prefix = path.join("/", assets_dist); // eg: "js/marketplace.bundle.6SCSPSGQ.js" for (const file of files) { const source_path = path.join(dist_path, file); const dest_path = path.join(sites_path, assets_dist, file); // Copy asset file from app/public to sites/assets if (!fs.existsSync(dest_path)) { const dest_dir = path.dirname(dest_path); fs.mkdirSync(dest_dir, { recursive: true }); fs.copyFileSync(source_path, dest_path); } // eg: [ "marketplace", "bundle", "6SCSPSGQ", "js" ] const parts = path.basename(file).split("."); // eg: "marketplace.bundle.js" const key = [...parts.slice(0, -2), parts.at(-1)].join("."); // eg: "js/marketplace.bundle.6SCSPSGQ.js" const value = path.join(prefix, file); if (file.includes("-rtl")) { assets_rtl[`rtl_${key}`] = value; } else { assets[key] = value; } } } function build_assets_for_apps(apps, files) { let { include_patterns, ignore_patterns } = files.length ? get_files_to_build(files) : get_all_files_to_build(apps); return glob(include_patterns, { ignore: ignore_patterns }).then((files) => { let output_path = assets_path; let file_map = {}; let style_file_map = {}; let rtl_style_file_map = {}; for (let file of files) { let relative_app_path = path.relative(apps_path, file); let app = relative_app_path.split(path.sep)[0]; let extension = path.extname(file); let output_name = path.basename(file, extension); if ([".css", ".scss", ".less", ".sass", ".styl"].includes(extension)) { output_name = path.join("css", output_name); } else if ([".js", ".ts"].includes(extension)) { output_name = path.join("js", output_name); } output_name = path.join(app, "dist", output_name); if ( Object.keys(file_map).includes(output_name) || Object.keys(style_file_map).includes(output_name) ) { log_warn(`Duplicate output file ${output_name} generated from ${file}`); } if ([".css", ".scss", ".less", ".sass", ".styl"].includes(extension)) { style_file_map[output_name] = file; rtl_style_file_map[output_name.replace("/css/", "/css-rtl/")] = file; } else { file_map[output_name] = file; } } let build = build_files({ files: file_map, outdir: output_path, }); let style_build = build_style_files({ files: style_file_map, outdir: output_path, }); let rtl_style_build = build_style_files({ files: rtl_style_file_map, outdir: output_path, rtl_style: true, }); return Promise.all([build, style_build, rtl_style_build]); }); } function get_all_files_to_build(apps) { let include_patterns = []; let ignore_patterns = []; for (let app of apps) { let public_path = get_public_path(app); include_patterns.push( path.resolve(public_path, "**", "*.bundle.{js,ts,css,sass,scss,less,styl,jsx}") ); ignore_patterns.push( path.resolve(public_path, "node_modules"), path.resolve(public_path, "dist") ); } return { include_patterns, ignore_patterns, }; } function get_files_to_build(files) { // files: ['frappe/website.bundle.js', 'erpnext/main.bundle.js'] let include_patterns = []; let ignore_patterns = []; for (let file of files) { let [app, bundle] = file.split("/"); let public_path = get_public_path(app); include_patterns.push(path.resolve(public_path, "**", bundle)); ignore_patterns.push( path.resolve(public_path, "node_modules"), path.resolve(public_path, "dist") ); } return { include_patterns, ignore_patterns, }; } function build_files({ files, outdir }) { let build_plugins = [vue(), html_plugin, build_cleanup_plugin, vue_style_plugin]; return esbuild.build(get_build_options(files, outdir, build_plugins)); } function build_style_files({ files, outdir, rtl_style = false }) { let plugins = []; if (rtl_style) { plugins.push(rtlcss); } let build_plugins = [ ignore_assets, build_cleanup_plugin, postCssPlugin({ plugins: plugins, sassOptions: sass_options, }), ]; plugins.push(require("autoprefixer")); return esbuild.build(get_build_options(files, outdir, build_plugins)); } function get_build_options(files, outdir, plugins) { return { entryPoints: files, entryNames: "[dir]/[name].[hash]", target: ["es2017"], outdir, sourcemap: true, bundle: true, metafile: true, minify: PRODUCTION, nodePaths: NODE_PATHS, define: { "process.env.NODE_ENV": JSON.stringify(PRODUCTION ? "production" : "development"), __VUE_OPTIONS_API__: JSON.stringify(true), __VUE_PROD_DEVTOOLS__: JSON.stringify(false), }, plugins: plugins, watch: get_watch_config(), }; } function get_watch_config() { if (WATCH_MODE) { return { async onRebuild(error, result) { if (error) { log_error("There was an error during rebuilding changes."); log(); log(chalk.dim(error.stack)); notify_redis({ error }); } else { let { new_assets_json, prev_assets_json } = await write_assets_json( result.metafile ); let changed_files; if (prev_assets_json) { changed_files = get_rebuilt_assets(prev_assets_json, new_assets_json); let timestamp = new Date().toLocaleTimeString(); let message = `${timestamp}: Compiled ${changed_files.length} files...`; log(chalk.yellow(message)); for (let filepath of changed_files) { let filename = path.basename(filepath); log(" " + filename); } log(); } notify_redis({ success: true, changed_files }); } }, }; } return null; } function log_built_assets(results) { let outputs = {}; for (const result of results) { outputs = Object.assign(outputs, result.metafile.outputs); } let column_widths = [60, 20]; cliui.div( { text: chalk.cyan.bold("File"), width: column_widths[0], }, { text: chalk.cyan.bold("Size"), width: column_widths[1], } ); cliui.div(""); let output_by_dist_path = {}; for (let outfile in outputs) { if (outfile.endsWith(".map")) continue; let data = outputs[outfile]; outfile = path.resolve(outfile); outfile = path.relative(assets_path, outfile); let filename = path.basename(outfile); let dist_path = outfile.replace(filename, ""); output_by_dist_path[dist_path] = output_by_dist_path[dist_path] || []; output_by_dist_path[dist_path].push({ name: filename, size: (data.bytes / 1000).toFixed(2) + " Kb", }); } for (let dist_path in output_by_dist_path) { let files = output_by_dist_path[dist_path]; cliui.div({ text: dist_path, width: column_widths[0], }); for (let i in files) { let file = files[i]; let branch = ""; if (i < files.length - 1) { branch = "├─ "; } else { branch = "└─ "; } let color = file.name.endsWith(".js") ? "green" : "blue"; cliui.div( { text: branch + chalk[color]("" + file.name), width: column_widths[0], }, { text: file.size, width: column_widths[1], } ); } cliui.div(""); } log(cliui.toString()); } // to store previous build's assets.json for comparison let prev_assets_json; let curr_assets_json; async function write_assets_json(metafile) { let rtl = false; prev_assets_json = curr_assets_json; let out = {}; for (let output in metafile.outputs) { let info = metafile.outputs[output]; let asset_path = "/" + path.relative(sites_path, output); if (info.entryPoint) { let key = path.basename(info.entryPoint); if (key.endsWith(".css") && asset_path.includes("/css-rtl/")) { rtl = true; key = `rtl_${key}`; } out[key] = asset_path; } } let { obj: assets_json, path: assets_json_path } = await get_assets_json_path_and_obj(rtl); // update with new values let new_assets_json = Object.assign({}, assets_json, out); curr_assets_json = new_assets_json; await fs.promises.writeFile(assets_json_path, JSON.stringify(new_assets_json, null, 4)); await update_assets_json_in_cache(); if (argv["save-metafiles"]) { // use current timestamp in readable formate as a suffix for filename let current_timestamp = new Date().getTime(); const metafile_name = `meta-${current_timestamp}.json`; await fs.promises.writeFile(`${metafile_name}`, JSON.stringify(metafile)); log(`Saved metafile as ${metafile_name}`); } return { new_assets_json, prev_assets_json, }; } async function update_assets_json_in_cache() { // Redis won't be present during docker image build if (process.env.FRAPPE_DOCKER_BUILD) { return; } // update assets_json cache in redis, so that it can be read directly by python let client = get_redis_subscriber("redis_cache"); // handle error event to avoid printing stack traces try { await client.connect(); } catch (e) { log_warn("Cannot connect to redis_cache to update assets_json"); } client.del("assets_json", (err) => { client.unref(); }); } async function get_assets_json_path_and_obj(is_rtl) { const file_name = is_rtl ? "assets-rtl.json" : "assets.json"; const assets_json_path = path.resolve(assets_path, file_name); let assets_json; try { assets_json = await fs.promises.readFile(assets_json_path, "utf-8"); } catch (error) { assets_json = "{}"; } assets_json = JSON.parse(assets_json); return { obj: assets_json, path: assets_json_path }; } function run_build_command_for_apps(apps) { let cwd = process.cwd(); let { execSync } = require("child_process"); for (let app of apps) { if (app === "frappe") continue; let root_app_path = path.resolve(apps_path, app); let package_json = path.resolve(root_app_path, "package.json"); let node_modules = path.resolve(root_app_path, "node_modules"); if (!fs.existsSync(package_json)) { continue; } let { scripts } = require(package_json); if (!scripts?.build) { continue; } process.chdir(root_app_path); if (!fs.existsSync(node_modules)) { log( `\nInstalling dependencies for ${chalk.bold(app)} (because node_modules not found)` ); execSync("yarn install --frozen-lockfile", { encoding: "utf8", stdio: "inherit" }); } log("\nRunning build command for", chalk.bold(app)); execSync("yarn build", { encoding: "utf8", stdio: "inherit" }); } process.chdir(cwd); } async function notify_redis({ error, success, changed_files }) { // notify redis which in turns tells socketio to publish this to browser let subscriber = get_redis_subscriber("redis_queue"); try { await subscriber.connect(); } catch (e) { log_warn("Cannot connect to redis_queue for browser events"); } let payload = null; if (error) { let formatted = await esbuild.formatMessages(error.errors, { kind: "error", terminalWidth: 100, }); let stack = error.stack.replace(new RegExp(bench_path, "g"), ""); payload = { error, formatted, stack, }; } if (success) { payload = { success: true, changed_files, live_reload: argv["live-reload"], }; } await subscriber.publish( "events", JSON.stringify({ event: "build_event", message: payload, }) ); } async function open_in_editor() { let subscriber = get_redis_subscriber("redis_queue"); try { await subscriber.connect(); } catch (e) { log_warn("Cannot connect to redis_queue for open_in_editor events"); } subscriber.subscribe("open_in_editor", (file) => { file = JSON.parse(file); let file_path = path.resolve(file.file); log("Opening file in editor:", file_path); let launch = require("launch-editor"); launch(`${file_path}:${file.line}:${file.column}`); }); } function get_rebuilt_assets(prev_assets, new_assets) { let added_files = []; let old_files = Object.values(prev_assets); let new_files = Object.values(new_assets); for (let filepath of new_files) { if (!old_files.includes(filepath)) { added_files.push(filepath); } } return added_files; } 这是完整文件 生产模式禁用 watch
最新发布
09-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值