首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 文件操作大全:建立、讀寫、屬性、目錄遍歷、隨機訪問實戰

     編輯:Java 相關知識

核心 API 概覽 (java.io / java.nio.file)

場景傳統 IO (java.io)現代 NIO.2 (java.nio.file)
文件/目錄元數據FilePath, Files, BasicFileAttributes
文本讀寫FileReader/Writer, BufferedReader/WriterFiles.readAllLines, Files.newBufferedReader, Files.write
二進制讀寫FileInputStream/OutputStream, BufferedInputStream/OutputStreamFiles.newInputStream, Files.newOutputStream, Files.readAllBytes
隨機訪問RandomAccessFileSeekableByteChannel
目錄遍歷File.listFiles()Files.walk, Files.walkFileTree, DirectoryStream

1. 文件/目錄建立、檢查、刪除

// NIO.2 風格 (推薦)
Path file = Paths.get("/tmp/demo.txt");
Path dir = Paths.get("/tmp/demo-dir");

Files.createDirectories(dir);                    // 遞歸建立目錄
Files.createFile(file);                          // 建立文件 (存在則拋異常)
Files.deleteIfExists(file);                      // 存在才刪除,不存在不報錯
Files.deleteIfExists(dir);                       // 目錄必須為空

// 傳統 File 風格
File f = new File("/tmp/demo.txt");
f.getParentFile().mkdirs();                      // 確保父目錄存在
f.createNewFile();                               // 返回 boolean
f.delete();                                      // 返回 boolean

2. 文件屬性查詢

Path path = Paths.get("/tmp/demo.txt");
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);

System.out.println("是否文件: " + attrs.isRegularFile());
System.out.println("是否目錄: " + attrs.isDirectory());
System.out.println("大小: " + attrs.size() + " bytes");
System.out.println("創建時間: " + attrs.creationTime());
System.out.println("最後修改: " + attrs.lastModifiedTime());
System.out.println("最後訪問: " + attrs.lastAccessTime());

// 權限檢查
System.out.println("可讀: " + Files.isReadable(path));
System.out.println("可寫: " + Files.isWritable(path));
System.out.println("可執行: " + Files.isExecutable(path));
System.out.println("隱藏: " + Files.isHidden(path));

3. 文本讀取:逐行處理 (大文件首選)

// NIO.2 + try-with-resources (自動關閉)
Path path = Paths.get("/var/log/app.log");
try (Stream lines = Files.lines(path, StandardCharsets.UTF_8)) {
    lines.filter(line -> line.contains("ERROR"))
         .forEach(System.out::println);
}

// 傳統 BufferedReader
try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    String line;
    while ((line = br.readLine()) != null) {
        // 處理每行
    }
}

4. 文本寫入:覆蓋 / 追加 / 帶換行

Path path = Paths.get("/tmp/output.txt");
List lines = List.of("第一行", "第二行", "第三行");

// 覆蓋寫入 (自動換行)
Files.write(path, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

// 追加寫入
Files.write(path, List.of("追加行"), StandardCharsets.UTF_8, 
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);

// BufferedWriter 精細控制
try (BufferedWriter bw = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) {
    bw.write("手動控制");
    bw.newLine();          // 跨平台換行
    bw.flush();            // 強制刷新到磁盤
}

5. 二進制讀寫

// 讀取全部位元組 (小文件)
byte[] data = Files.readAllBytes(Paths.get("/tmp/image.png"));

// 流式寫入 (大文件)
try (InputStream in = Files.newInputStream(Paths.get("/big/in.dat"));
     OutputStream out = Files.newOutputStream(Paths.get("/big/out.dat"),
             StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
    byte[] buffer = new byte[8192];
    int len;
    while ((len = in.read(buffer)) != -1) {
        out.write(buffer, 0, len);
    }
}

6. 目錄遍歷三種方式

Path dir = Paths.get("/project/src");

// 1. Files.walk (Stream, 深度優先, 可限制深度)
try (Stream stream = Files.walk(dir, 3, FileVisitOption.FOLLOW_LINKS)) {
    stream.filter(Files::isRegularFile)
          .filter(p -> p.toString().endsWith(".java"))
          .forEach(System.out::println);
}

// 2. Files.walkFileTree (Visitor 模式, 完全控制)
Files.walkFileTree(dir, new SimpleFileVisitor() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        if (file.toString().endsWith(".class")) {
            System.out.println("編譯產物: " + file);
        }
        return FileVisitResult.CONTINUE;
    }
    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        log.warn("無法訪問: " + file, exc);
        return FileVisitResult.CONTINUE;
    }
});

// 3. DirectoryStream (僅當前目錄, 低記憶體)
try (DirectoryStream stream = Files.newDirectoryStream(dir, "*.java")) {
    for (Path entry : stream) System.out.println(entry);
}

7. 隨機訪問:RandomAccessFile / SeekableByteChannel

// 隨機讀寫特定位置
try (RandomAccessFile raf = new RandomAccessFile("/tmp/data.bin", "rw")) {
    raf.seek(100);              // 跳到第 100 字節
    raf.writeInt(0xCAFEBABE);   // 寫入 int
    raf.seek(100);
    int val = raf.readInt();    // 讀回驗證
}

// NIO.2 通道版
try (SeekableByteChannel ch = Files.newByteChannel(
        Paths.get("/tmp/data.bin"),
        StandardOpenOption.READ, StandardOpenOption.WRITE)) {
    ch.position(100);
    ByteBuffer buf = ByteBuffer.allocate(4).putInt(0xCAFEBABE);
    buf.flip();
    ch.write(buf);
}

8. 判斷空文件 / 讀取到文件末尾

// NIO.2
boolean empty = Files.size(path) == 0;

// 傳統
try (FileReader fr = new FileReader(path)) {
    boolean empty = fr.read() == -1; // 首次讀取即返回 -1 表示空
}

9. 編碼處理鐵律

  • 顯式指定 Charset:StandardCharsets.UTF_8,絕不依賴平台默認編碼
  • 讀取未知編碼文件:嘗試 UTF-8 → 失敗嘗試 GBK/ISO-8859-1,或用 juniversalchardet 自動檢測

10. 常見坑與最佳實踐

坑點正確姿勢
相對路徑依賴工作目錄用 Path.of("").toAbsolutePath() 或配置絕對路徑
大文件 readAllBytes/readAllLines 導致 OOM流式處理 Files.lines()/InputStream
忘記關閉流/通道全程 try-with-resources
Windows 路徑分隔符 \ 轉義問題用 Paths.get("C:/data", "file.txt") 或 Path.of("C:", "data", "file.txt")
併發寫入同一文件數據競爭文件鎖 FileChannel.lock()、寫臨時文件再 Files.move(ATOMIC_MOVE)

NIO.2 (JDK 7+) 是現代 Java 文件操作標準:API 更清晰、異常更豐富、支持符號鏈接、屬性讀取、Stream 化處理。新代碼請優先選用 Path/Files。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved