Java NIO之FileChannel 詳解

關鍵點說明

  1. 文件打開選項

    • StandardOpenOption.CREATE?- 文件不存在時創建

    • StandardOpenOption.READ/WRITE?- 讀寫權限

    • StandardOpenOption.APPEND?- 追加模式

    • StandardOpenOption.TRUNCATE_EXISTING?- 清空已存在文件

  2. 緩沖區操作

    • ByteBuffer.wrap()?包裝現有字節數組

    • buffer.flip()?切換讀寫模式

    • 直接操作緩沖區提高性能

  3. 高效文件復制

    • transferTo()/transferFrom()?方法比傳統流復制更高效

  4. 資源管理

    • 使用try-with-resources確保通道自動關閉

    • 文件鎖需要顯式釋放

這些示例展示了FileChannel的基本讀寫操作、文件鎖的使用以及內存映射文件的高效操作,可以根據實際需求進行調整和擴展。

1. 基本文件讀寫示例

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class FileChannelDemo {public static void main(String[] args) {String filePath = "test.txt";// 寫入文件writeToFile(filePath, "Hello, FileChannel!");// 讀取文件String content = readFromFile(filePath);System.out.println("文件內容: " + content);// 追加內容appendToFile(filePath, "\n這是追加的內容");// 再次讀取System.out.println("追加后的內容: " + readFromFile(filePath));// 文件復制copyFile(filePath, "test_copy.txt");System.out.println("復制文件內容: " + readFromFile("test_copy.txt"));}// 寫入文件(覆蓋)public static void writeToFile(String filePath, String content) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.CREATE,StandardOpenOption.WRITE,StandardOpenOption.TRUNCATE_EXISTING)) {ByteBuffer buffer = ByteBuffer.wrap(content.getBytes());channel.write(buffer);System.out.println("寫入文件成功");} catch (IOException e) {e.printStackTrace();}}// 讀取文件public static String readFromFile(String filePath) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.READ)) {ByteBuffer buffer = ByteBuffer.allocate((int) channel.size());channel.read(buffer);buffer.flip();return new String(buffer.array(), 0, buffer.limit());} catch (IOException e) {e.printStackTrace();return null;}}// 追加內容到文件public static void appendToFile(String filePath, String content) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.WRITE,StandardOpenOption.APPEND)) {ByteBuffer buffer = ByteBuffer.wrap(content.getBytes());channel.write(buffer);System.out.println("追加內容成功");} catch (IOException e) {e.printStackTrace();}}// 文件復制public static void copyFile(String sourcePath, String targetPath) {try (FileChannel source = FileChannel.open(Paths.get(sourcePath),StandardOpenOption.READ);FileChannel target = FileChannel.open(Paths.get(targetPath),StandardOpenOption.CREATE,StandardOpenOption.WRITE,StandardOpenOption.TRUNCATE_EXISTING)) {// 使用transferTo進行高效的文件復制source.transferTo(0, source.size(), target);System.out.println("文件復制成功");} catch (IOException e) {e.printStackTrace();}}
}

2. 使用文件鎖的讀寫示例

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class FileChannelWithLockDemo {public static void main(String[] args) {String filePath = "locked_file.txt";// 線程1 - 寫入數據new Thread(() -> {writeWithLock(filePath, "線程1寫入的數據");}).start();// 線程2 - 嘗試寫入new Thread(() -> {writeWithLock(filePath, "線程2寫入的數據");}).start();}public static void writeWithLock(String filePath, String content) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.CREATE,StandardOpenOption.WRITE,StandardOpenOption.APPEND)) {// 嘗試獲取排他鎖System.out.println(Thread.currentThread().getName() + " 嘗試獲取文件鎖...");FileLock lock = channel.lock();try {System.out.println(Thread.currentThread().getName() + " 獲取到文件鎖");// 模擬耗時操作Thread.sleep(2000);// 寫入數據ByteBuffer buffer = ByteBuffer.wrap((content + "\n").getBytes());channel.write(buffer);System.out.println(Thread.currentThread().getName() + " 寫入完成");} finally {lock.release();System.out.println(Thread.currentThread().getName() + " 釋放文件鎖");}} catch (IOException | InterruptedException e) {e.printStackTrace();}}
}

3.內存映射文件示例

import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class MemoryMappedFileDemo {public static void main(String[] args) {String filePath = "mapped_file.txt";// 寫入內存映射文件writeMappedFile(filePath, "這是內存映射文件的內容");// 讀取內存映射文件readMappedFile(filePath);}public static void writeMappedFile(String filePath, String content) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE)) {// 創建內存映射MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, content.getBytes().length);// 直接操作內存buffer.put(content.getBytes());System.out.println("內存映射文件寫入完成");} catch (IOException e) {e.printStackTrace();}}public static void readMappedFile(String filePath) {try (FileChannel channel = FileChannel.open(Paths.get(filePath),StandardOpenOption.READ)) {MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());byte[] bytes = new byte[(int) channel.size()];buffer.get(bytes);System.out.println("讀取到的內容: " + new String(bytes));} catch (IOException e) {e.printStackTrace();}}
}

FileChannel的lock詳解

一、文件鎖的基本概念

文件鎖分為兩種類型:

  1. 排他鎖(獨占鎖)

    • 同一時間只能有一個進程持有

    • 其他進程無法獲取任何類型的鎖

  2. 共享鎖(讀鎖)

    • 可以被多個進程同時持有

    • 但只要有進程持有共享鎖,就不能獲取排他鎖

二、lock()方法的使用

1. 基本鎖定方式

FileChannel channel = FileChannel.open(Paths.get("test.txt"), StandardOpenOption.READ, StandardOpenOption.WRITE);// 獲取排他鎖(默認)
FileLock exclusiveLock = channel.lock();// 獲取共享鎖(第三個參數為true)
FileLock sharedLock = channel.lock(0, Long.MAX_VALUE, true);

2. 方法參數說明

public final FileLock lock(long position, long size, boolean shared)
  • position:鎖定區域的起始位置

  • size:鎖定區域的大小(比特)

  • shared:是否為共享鎖(true=共享鎖,false=排他鎖)

3.非阻塞嘗試鎖定

FileLock tryLock = channel.tryLock(); // 非阻塞版本
if (tryLock == null) {// 獲取鎖失敗
}
tryLock.release()

四、注意事項

  1. 鎖的有效性

    • 文件鎖是建議性的(advisory),不是強制性的

    • 只有遵守鎖協議的進程才會受鎖影響

    • 操作系統可能有不同的實現方式

  2. 性能考慮

    • 頻繁獲取/釋放鎖會影響性能

    • 鎖定大文件區域可能降低并發性

  3. 異常處理

    • OverlappingFileLockException:當請求的鎖區域與現有鎖重疊時拋出

    • NonWritableChannelException:嘗試在只讀通道上獲取排他鎖

  4. 平臺差異

    • Windows系統上的實現與Unix-like系統不同

    • 某些網絡文件系統可能不支持文件鎖

五、適用場景

  1. 多進程共享文件訪問控制

  2. 防止文件被多個寫入者同時修改

  3. 實現簡單的進程間同步機制

  4. 保護關鍵配置文件不被并發修改

正確使用FileChannel的鎖機制可以有效地管理對共享文件的并發訪問,保證數據的一致性和完整性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74917.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74917.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74917.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

stock-pandas,一個易用的talib的替代開源庫。

原創內容第841篇,專注智能量化投資、個人成長與財富自由。 介紹一個ta-lib的平替——我們來實現一下,最高價突破布林帶上軌,和最低價突破布林帶下軌的可視化效果: cross_up_upper stock[high].copy()# cross_up_upper 最高價突破…

JVM 面經

1、什么是 JVM? JVM 就是 Java 虛擬機,它是 Java 實現跨平臺的基石。程序運行之前,需要先通過編譯器將 Java 源代碼文件編譯成 Java 字節碼文件;程序運行時,JVM 會對字節碼文件進行逐行解釋,翻譯成機器碼指令&#x…

【JavaScript】合體期功法——DOM(一)

目錄 DOMWeb API 基本概念作用和分類 什么是 DOMDOM 樹DOM 對象 獲取 DOM 元素根據 CSS 選擇器來獲取 DOM 元素選擇匹配的第一個元素選擇匹配的多個元素 其他獲取 DOM 元素方法 修改元素的內容對象.innerText 屬性對象.innerHTML 屬性案例:年會抽獎 修改元素屬性修改…

GAMMA數據處理(十)

今天向別人請教了一個問題,剛無意中搜索到了一模一樣的問題 不知道這個怎么解決... ok 解決了 有一個GAMMA的命令可轉換 但是很奇怪 完全對不上 轉換出來的行列號 不知道為啥 再試試 是因為經緯度坐標的小數點位數 de as

Java入門知識總結——章節(二)

ps:本章主要講數組、二維數組、變量 一、數組 數組是一個數據容器,可用來存儲一批同類型的數據 🔑:注意 類也可以是一個類的數組 public class Main {public static class Student {String name;int age; // 移除 unsignedint…

動態IP:網絡世界的“變色龍”如何改變你的在線體驗?

你知道嗎?有時候我覺得動態IP就像是網絡世界里的“變色龍”。它不像靜態IP那樣一成不變,而是隨時在變化,像是一個永遠在換衣服的演員。你永遠不知道它下一秒會變成什么樣子,但正是這種不確定性,讓它變得特別有趣。想象…

從24GHz到71GHz:Sivers半導體的廣泛頻率范圍5G毫米波產品解析

在5G技術的浪潮中,Sivers半導體推出了創新的毫米波無線產品,為通信行業帶來高效、可靠的解決方案。這些產品支持從24GHz到71GHz的頻率,覆蓋許可與非許可頻段,適應高速、低延遲的通信場景。 5G通信頻段的一點事兒及Sivers毫米波射頻…

aocache:AOCache 新增功能深度解析:從性能監控到靈活配置的全方位升級

最近對aocache 進行了重要升級,最新版本0.6.0增加了幾項新功能:性能分析日志,AOCache性能分析工具,切入點自定義配置,全局配置,本文詳細說明這幾項目新功能的作用和使用方式。 一、性能分析日志 需求背景…

Java EE 進階:MyBatis-plus

MyBatis-plus的介紹 MyBatis-plus是MyBatis的增強工具,在MyBatis的基礎上做出加強,只要MyBatis有的功能MyBatis-plus都有。 MyBatis-plus的上手 添加依賴 在我們創建項目的時候,我們需要添加MyBatis-plus和mysql的依賴 MyBatis-plus的依賴…

GitHub和Gitee上的一些AI項目

以下是GitHub和Gitee上的一些AI項目: GitHub上的AI項目 TensorFlow:一個端到端開源機器學習平臺,包含大量工具和庫,廣泛應用于圖像識別、自然語言處理等領域。PyTorch:由Facebook開發的開源深度學習框架,…

JavaScript網頁設計高級案例:構建交互式圖片畫廊

JavaScript網頁設計高級案例:構建交互式圖片畫廊 在現代Web開發中,交互式元素已成為提升用戶體驗的關鍵因素。本文將通過一個高級案例 - 構建交互式圖片畫廊,展示如何結合HTML和JavaScript創建引人入勝的網頁應用。這個案例不僅涵蓋了基礎的…

Linux命令大全:從入門到高效運維

適合人群:Linux新手 | 運維工程師 | 開發者 目錄 一、Linux常用命令(每天必用) 1. 文件與目錄操作 2. 文件內容查看與編輯 二、次常用命令(按需使用) 1. 系統管理與監控 2. 網絡與通信 3. 權限與用戶管理 三、…

Windows 10/11 使用 VSCode + SSH 免密遠程連接 Ubuntu 服務器(指定端口)

摘要: 本文詳細介紹如何在 Windows 系統上通過 VSCode Remote-SSH 免密登錄遠程 Ubuntu 服務器(SSH 端口 2202),避免每次輸入密碼的繁瑣操作,提高開發效率。 1. 環境準備 本地系統:Windows 10/11遠程服務…

一些需要學習的C++庫:CGAL和Eysshot

寫在前面: 從開始工作到現在,去過多家公司,多個行業, 雖然大部分時間在通信業,但也有其它的行業的工作沒有做完,但也很感興趣。每次想要研究一下時,總是想不起來。 這里寫一些信息,…

藍橋杯16天刷題計劃一一Day01

藍橋杯16天刷題計劃一一Day01(STL練習) 作者:blue 時間:2025.3.26 文章目錄 藍橋杯16天刷題計劃一一Day01(STL練習)[P1540 [NOIP 2010 提高組\] 機器翻譯 - 洛谷 (luogu.com.cn)](https://www.luogu.com.…

相對位置2d矩陣和kron運算的思考

文章目錄 1. 相對位置矩陣2d2. kron運算 1. 相對位置矩陣2d 在swin-transformer中,我們會計算每個patch之間的相對位置,那么我們看到有一連串的拉伸和相減,直接貼代碼: import torch import torch.nn as nntorch.set_printoptio…

Redis 版本演進及主要新特性

Redis 版本發布歷史 穩定版本時間線 Redis 2.6 (2012年)Redis 2.8 (2013年11月)Redis 3.0 (2015年4月) - 首次支持集群Redis 3.2 (2016年5月)Redis 4.0 (2017年7月)Redis 5.0 (2018年10月)Redis 6.0 (2020年4月)Redis 6.2 (2021年2月)Redis 7.0 (2022年4月) - 最新穩定版(截至…

HTML5 Geolocation(地理定位)學習筆記

一、HTML5 Geolocation簡介 HTML5 Geolocation(地理定位)API用于獲取用戶的地理位置信息。通過這個API,可以獲取用戶的緯度、經度、海拔等信息。由于地理定位可能涉及用戶隱私,因此只有在用戶同意的情況下,才能獲取其…

愛普生VG3225EFN壓控晶振5G基站低噪聲的解決方案

在 5G 通信網絡的高速發展中,系統噪聲的控制成為保障網絡可靠性與數據吞吐量的關鍵。愛普生 VG3225EFN 壓控晶振憑借其卓越的低噪聲特性,成為 5G 基站時鐘系統的理想選擇。通過創新的技術設計,這款晶振不僅為基站提供了穩定的時鐘基準&#x…

【問題解決】Linux安裝conda修改~/.bashrc配置文件后,root 用戶下顯示 -bash-4.2#

問題描述 在Linux安裝conda下的python環境時候,修改了~/.bashrc文件,修改完成后,再次進入服務器后,登錄時候顯示的不是正常的[rootlocalhost ~]#,而是-bash-4.2# 原因分析: 網上原因有:/root下…