用Java比较文件
我正在為PACKT創建一系列有關Java網絡編程的視頻教程。 有整節關于Java NIO。 一個示例程序是通過原始套接字連接將文件從客戶端復制到服務器。 客戶端從磁盤讀取文件,服務器將到達的字節保存到磁盤。 因為這是一個演示,所以服務器和客戶端在同一臺計算機上運行,??并且文件從一個目錄復制到完全相同的目錄,但名稱不同。 布丁的證明正在吃掉:文件必須進行比較。
我要復制的文件已創建為包含隨機字節。 僅傳輸文本信息有時會在代碼中留下一些棘手的錯誤。 隨機文件是使用簡單的Java類創建的:
package packt.java9.network.niodemo;import java.io.FileOutputStream; import java.io.IOException; import java.util.Random;public class SampleMaker {public static void main(String[] args) throws IOException {byte[] buffer = new byte[1024 * 1024 * 10];try (FileOutputStream fos = new FileOutputStream("sample.txt")) {Random random = new Random();for (int i = 0; i < 16; i++) {random.nextBytes(buffer);fos.write(buffer);}}} }使用IntelliJ比較文件相當容易,但是由于文件是二進制文件且很大,因此這種方法并不是真正的最佳選擇。 我決定編寫一個簡短的程序,該程序不僅可以表明文件不同,還可以表明不同之處。 代碼非常簡單:
package packt.java9.network.niodemo;import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException;public class SampleCompare {public static void main(String[] args) throws IOException {long start = System.nanoTime();BufferedInputStream fis1 = new BufferedInputStream(new FileInputStream("sample.txt"));BufferedInputStream fis2 = new BufferedInputStream(new FileInputStream("sample-copy.txt"));int b1 = 0, b2 = 0, pos = 1;while (b1 != -1 && b2 != -1) {if (b1 != b2) {System.out.println("Files differ at position " + pos);}pos++;b1 = fis1.read();b2 = fis2.read();}if (b1 != b2) {System.out.println("Files have different length");} else {System.out.println("Files are identical, you can delete one of them.");}fis1.close();fis2.close();long end = System.nanoTime();System.out.print("Execution time: " + (end - start)/1000000 + "ms");} }在裝有SSD的Mac Book上,比較這兩個160MB文件的運行時間約為6秒,如果我指定一個較大的緩沖區(例如10MB)作為BufferedInputStream構造函數的第二個參數,則運行時間不會顯著改善。 (另一方面,如果我們不使用BufferedInputStream那么時間大約是十倍。)這是可以接受的,但是如果我只是diff sample.txt sample-copy.txt發出diff sample.txt sample-copy.txt ,那么響應明顯更快,而不是6秒。 可能有很多事情,例如Java啟動時間, while循環開始時的代碼解釋,直到JIT編譯器認為是開始工作的時候。 我的直覺是,代碼會花費大部分時間將文件讀入內存。 將字節讀取到緩沖區是一個復雜的過程。 它涉及操作系統,設備驅動程序,JVM實現,它們將字節從一個位置移到另一位置,最后我們只比較字節,沒有別的。 可以用更簡單的方式完成。 我們可以要求操作系統為我們做這件事,并跳過大多數Java運行時活動,文件緩沖區和其他閃爍。
我們可以要求操作系統將文件讀取到內存中,然后從它們所在的位置逐個讀取字節。 我們不需要一個緩沖區,該緩沖區屬于Java對象,并且會占用堆空間。 我們可以使用內存映射文件。 畢竟,內存映射文件使用Java NIO,而這正是當前正在制作的教程視頻部分的主題。
操作系統將內存映射文件讀入內存,并且字節可供Java程序使用。 內存是由操作系統分配的,它不會消耗堆內存。 如果Java代碼修改了映射內存的內容,則操作系統會在認為適當時以優化方式將更改寫入磁盤。 但是,這并不意味著如果JVM崩潰,數據就會丟失。 當Java代碼修改內存映射文件的內存時,它將修改屬于操作系統的內存,該內存在JVM停止運行后可用并且有效。 無法保證并100%防止電源中斷和硬件崩潰,但這是非常低的水平。 如果有人對此感到恐懼,那么保護應該在Java無關的硬件級別上進行。 使用內存映射文件,我們可以確保將數據以一定的非常高的概率保存到磁盤中,只有通過容錯硬件,群集,不間斷電源等才能增加數據。 這些不是Java。 如果確實需要使用Java進行某些操作才能將數據寫入磁盤,則可以調用MappedByteBuffer.force()方法,該方法要求操作系統將更改寫入磁盤。 但是,過于頻繁和不必要地調用它可能會影響性能。 (很簡單,因為它會將數據寫入磁盤,并且僅在操作系統提示已寫入數據時才返回。)
對于大文件,使用內存映射文件讀取和寫入數據通常要快得多。 為了獲得適當的性能,計算機應該有大量的內存,否則,只有部分文件保留在內存中,然后頁面錯誤會增加。 一件好事是,如果同一文件通過兩個或多個不同的進程映射到內存中,則將使用同一內存區域。 這樣,進程甚至可以相互通信。
使用內存映射文件的比較應用程序如下:
package packt.java9.network.niodemo;import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel;public class MapCompare {public static void main(String[] args) throws IOException {long start = System.nanoTime();FileChannel ch1 = new RandomAccessFile("sample.txt", "r").getChannel();FileChannel ch2 = new RandomAccessFile("sample-copy.txt", "r").getChannel();if (ch1.size() != ch2.size()) {System.out.println("Files have different length");return;}long size = ch1.size();ByteBuffer m1 = ch1.map(FileChannel.MapMode.READ_ONLY, 0L, size);ByteBuffer m2 = ch2.map(FileChannel.MapMode.READ_ONLY, 0L, size);for (int pos = 0; pos < size; pos++) {if (m1.get(pos) != m2.get(pos)) {System.out.println("Files differ at position " + pos);return;}}System.out.println("Files are identical, you can delete one of them.");long end = System.nanoTime();System.out.print("Execution time: " + (end - start) / 1000000 + "ms");} }為了對文件進行內存映射,我們必須首先使用RandomAccessFile類打開它們,然后從該對象中請求通道。 該通道可用于創建MappedByteBuffer ,它表示文件內容加載到的存儲區。 該方法map中的示例映射在只讀模式的文件,從該文件的文件的末尾的開始。 我們嘗試映射整個文件。 僅當文件大小不超過2GB時,此方法才有效。 起始位置很long但是要映射的區域的大小受Integer大小的限制。
通常來說...哦,是的,比較160MB隨機內容文件的運行時間約為1秒。
翻譯自: https://www.javacodegeeks.com/2018/02/comparing-files-java.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: sd卡 linux 驱动(sd卡 lin
- 下一篇: 安卓手机解锁工具软件(安卓手机解锁工具)