Java学习笔记——Java I/O
Java I/O
介绍
I/O 目标
在Java中,I/O(输入/输出)操作可以针对不同的目标进行,常见的I/O目标包括:
- 文件(File):从文件读取数据或将数据写入文件。Java提供了
File
类和相关的I/O类来处理文件操作。 - 控制台(Console):与用户交互,通过控制台读取用户输入或向控制台输出信息。Java提供了
System.in
和System.out
来进行基本的控制台I/O操作。 - 网络连接(Network Connection):通过网络连接进行数据的输入和输出。Java提供了
Socket
和ServerSocket
等类用于网络通信。
I/O 操作方式
I/O 操作可以按照数据的类型和读写方式进行分类:
- 文本型(字符型)/ 数据型(字节型):文本型I/O操作以字符为单位进行,通常用于处理文本文件。数据型I/O操作以字节为单位进行,通常用于处理二进制文件。Java提供了
Reader
和Writer
类来处理文本数据,以及InputStream
和OutputStream
类来处理字节数据。 - 顺序访问(Sequential)/ 随机访问(Random Access):顺序访问是按照数据的顺序一个接一个地进行读取或写入,而随机访问则允许直接跳转到文件的任意位置进行读取或写入。Java提供了相应的类,例如
FileReader
和FileWriter
用于顺序访问文本数据,以及RandomAccessFile
类用于随机访问数据。
这些不同的I/O目标和操作方式,使得Java在处理各种输入输出需求时更加灵活和强大。你可以根据具体的场景选择合适的I/O类和方法来完成相关任务。
一个项目:
List *.log from“c:\Windows”in descending order
import java.io.File; import java.util.Arrays; import java.util.Comparator; class LogFileManager { // 过滤以 ".log" 结尾的文件 private File[] filterLogFiles(File directory) { File[] files = directory.listFiles(); if (files != null && files.length > 0) { return Arrays.stream(files) .filter(file -> file.getName().endsWith(".log")) .toArray(File[]::new); } return new File[0]; } // 将文件按照降序排列 private void sortLogFilesDescending(File[] logFiles) { Arrays.sort(logFiles, Comparator.reverseOrder()); } // 递归遍历文件夹,包括所有子文件夹,找出所有以 ".log" 结尾的文件 private void listLogFilesRecursive(File directory) { File[] logFiles = filterLogFiles(directory); sortLogFilesDescending(logFiles); // 打印当前目录下的 ".log" 文件 for (File logFile : logFiles) { System.out.println(logFile.getAbsolutePath()); } // 递归遍历子文件夹 File[] subDirectories = directory.listFiles(File::isDirectory); if (subDirectories != null) { for (File subDirectory : subDirectories) { listLogFilesRecursive(subDirectory); } } } // 公共接口,用于启动递归遍历 public void listLogFiles(String directoryPath) { File directory = new File(directoryPath); if (directory.exists() && directory.isDirectory()) { // 调用递归函数开始遍历 listLogFilesRecursive(directory); } else { System.out.println("目录不存在或者不是一个文件夹。"); } } public static void main(String[] args) { LogFileManager logFileManager = new LogFileManager(); // 调用函数列出 "c:\\Windows" 目录下的所有以 ".log" 结尾的文件(包括所有子文件夹) logFileManager.listLogFiles("E:\\测试"); } }
Stream
流的概念
在计算机科学中,流(Stream)是一个抽象的概念,用于表示一系列连续的数据元素,可以是字节(byte)或字符(char)。流可以被看作是从源头到目的地的一个通道,数据通过这个通道流动,按照特定的顺序传输。在Java中,流主要分为字节流(Byte Stream)和字符流(Character Stream)。
字节流(Byte Stream) 表示以字节为单位的数据流。字节流主要用于处理 二进制 数据,比如文件的读写等。字节流是以字节为单位进行读写操作的。
字符流(Character Stream) 表示以字符为单位的数据流。字符流主要用于处理 文本数据 ,字符流会将字符按照字符编码集进行读写操作。
关于流的概念,有两个重要的方面需要注意:
- 数据传输的连续性: 流中的数据是连续不断地流动的,数据元素按照顺序一个接一个传递。
- FIFO(先进先出): 流可以被看作是一个FIFO通道,即数据按照先进先出的顺序进行传输。这意味着先被写入流的数据将会先被读取出来。
在处理文件、网络通信、输入输出等操作时,流的概念非常重要。流提供了一种方便的方式来读取和写入数据,它们使得数据的传输更加灵活、高效,并且保持了数据传输的顺序性。 在Java中,字节流(Byte Stream)和字符流(Character Stream)是用于处理输入和输出的两种基本类型的流。字节流用于处理二进制数据,而字符流则用于处理文本数据。下面是Java中java.io
包中抽象字节流和字符流类的一些方法的说明:
字节流(Byte Stream)
java.io.InputStream
(抽象字节输入流)
int read()
: 从输入流中读取一个字节的数据,并返回该字节的整数表示(0-255)。返回值为-1表示已经到达流的末尾。
java.io.OutputStream
(抽象字节输出流)
void write(int b)
: 向输出流中写入一个字节的数据。参数b
是一个整数,但只写入b
的低8位。因为Java中的byte
类型是8位,所以只写入最低8位。void write(byte[] b)
: 向输出流中写入byte
数组的数据。
字符流(Character Stream)
java.io.Reader
(抽象字符输入流)
int read()
: 从输入流中读取一个字符的数据,并返回该字符的整数表示(Unicode码)。返回值为-1表示已经到达流的末尾。
java.io.Writer
(抽象字符输出流)
void write(int b)
: 向输出流中写入一个字符的数据。参数b
是一个整数,但只写入b
的低16位。因为Java中的char
类型是16位。void write(char[] c)
: 向输出流中写入char
数组的数据。
关于为什么这些方法的参数类型选择了int
而不是byte
或char
,这是为了保持一致性。在Java中,整数类型的范围足够大,可以容纳byte
和char
的所有可能值,所以使用int
类型既可以处理字节数据也可以处理字符数据,同时保持了方法签名的一致性。这种设计决策简化了API,并提高了灵活性。
在java.io
包中,有多个类实现了字节流(Byte Stream)和字符流(Character Stream)的功能,这些类用于读取和写入文件、网络连接、内存等不同的数据源。以下是一些常用的实现了字节流和字符流的类:
字节流(Byte Stream)
字节输入流(Byte Input Stream):
FileInputStream
: 从文件中读取字节数据的输入流。PipedInputStream
: 用于从相关的PipedOutputStream
读取数据的输入流。ByteArrayInputStream
: 从字节数组中读取数据的输入流。BufferedInputStream
: 提供了缓冲功能,可以提高读取文件的性能。ObjectInputStream
: 用于从输入流中读取Java对象的输入流。
字节输出流(Byte Output Stream):
FileOutputStream
: 将字节数据写入文件的输出流。PipedOutputStream
: 用于向相关的PipedInputStream
发送数据的输出流。ByteArrayOutputStream
: 将字节数据写入字节数组的输出流。BufferedOutputStream
: 提供了缓冲功能,可以提高写入文件的性能。ObjectOutputStream
: 用于将Java对象写入输出流的输出流。
字符流(Character Stream)
字符输入流(Character Input Stream):
FileReader
: 从文件中读取字符数据的输入流。PipedReader
: 用于从相关的PipedWriter
读取数据的输入流。BufferedReader
: 提供了缓冲功能,可以提高读取文本文件的性能。InputStreamReader
: 将字节输入流转换为字符输入流的桥梁。
字符输出流(Character Output Stream):
FileWriter
: 将字符数据写入文件的输出流。PipedWriter
: 用于向相关的PipedReader
发送数据的输出流。BufferedWriter
: 提供了缓冲功能,可以提高写入文本文件的性能。OutputStreamWriter
: 将字符输出流转换为字节输出流的桥梁。
这些类提供了丰富的功能,可以满足不同场景下的读写需求。根据需要选择合适的流类,可以高效地进行文件读写、网络通信、数据处理等操作。
示例代码1
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class FileStreamTester { private FileInputStream fis; // 用于读取文件的字节输入流 private FileOutputStream fos; // 用于写入文件的字节输出流 // 构造函数,接受一个File对象参数,用于初始化输入输出流 public FileStreamTester(File file) throws IOException { createFile(file); // 调用createFile方法,确保文件存在 this.fis = new FileInputStream(file); // 初始化字节输入流 this.fos = new FileOutputStream(file,true); // 初始化字节输出流,加true表示续写,缺省或者false为覆盖 } // 静态方法,用于创建文件,如果文件不存在则创建一个新文件 public static void createFile(File file) throws IOException { if (!file.exists() || !file.isFile()) { file.createNewFile(); } } // 关闭输入输出流的方法 public void close() throws IOException { fis.close(); // 关闭字节输入流 fos.close(); // 关闭字节输出流 } // 从文件中读取一个字节的数据并返回,如果到达文件末尾则返回-1 public int read() throws IOException { return fis.read(); } // 向文件中写入一个字节的数据 public void write(int arg) throws IOException { fos.write(arg); } // 向文件中写入字节数组的数据 public void write(byte[] arg) throws IOException { fos.write(arg); } // 返回文件中可用于读取的字节数 public int available() throws IOException { return fis.available(); } // 主方法,程序的入口点 public static void main(String[] args) { try { File file = new File("d:/test.dat"); // 创建File对象,表示文件路径 FileStreamTester tester = new FileStreamTester(file); // 创建FileStreamTester对象 tester.write(97); // 将整数97写入文件(对应字符'a'的ASCII码) tester.write('b'); // 将字符'b'写入文件 tester.write(new String("好").getBytes()); System.out.println(tester.available() + " size"); // 打印文件中可用字节数 int i = tester.read(); // 从文件中读取一个字节的数据 while (i != -1) { // 如果读取的字节不是文件末尾标志-1(文件没结束),则继续读取并打印字符 System.out.println((char) i); // 将字节转换为字符并打印 i = tester.read(); // 继续读取下一个字节 } tester.close(); // 关闭输入输出流 } catch (IOException e) { e.printStackTrace(); // 捕获并打印IO异常 } } }
运行结果:
这段代码创建了一个FileStreamTester
类,用于演示文件的读取和写入操作。在main
方法中,它创建了一个文件,向文件中写入数据,然后再从文件中读取数据,并打印出来。
示例代码2
import java.io.*; public class TestWriter { public static void main(String[] args) throws IOException { // 创建文件对象 File file = new File("c:/text.txt"); // 使用FileWriter在文件末尾追加内容(true参数表示追加) FileWriter writer = new FileWriter(file, true); // 写入字符数组 "CoSE" writer.write("CoSE".toCharArray()); // 写入字符数组 "软件学院" writer.write("软件学院".toCharArray()); // 刷新缓冲区,确保内容被写入文件 writer.flush(); // 关闭写入流 writer.close(); // 读取文件内容 FileReader reader = new FileReader(file); int character; // 读取文件内容并输出 while ((character = reader.read()) != -1) { System.out.print((char) character); } // 关闭读取流 reader.close(); } }
在这个代码中,首先创建了一个File
对象表示文件路径。然后,使用FileWriter
在文件末尾追加内容。flush()
确保数据被写入文件。接着使用FileReader
读取文件内容,并在控制台输出。最后,关闭写入流和读取流。请确保文件路径正确,并注意在文件操作完成后关闭相应的流,以避免资源泄漏。
缓冲流(Buffered Stream)
缓冲流是在输入和输出流的基础上加入了缓冲区(内部数组),通过在内存中建立缓冲区,可以减少对磁盘的访问次数,从而提高读写的效率。下面是关于缓冲流的一些要点:
- 缓冲区: 缓冲流使用内部的字节数组作为缓冲区,读取和写入的数据在内存中进行缓存,当缓冲区满了或者达到一定条件时,再进行实际的读取和写入操作。
- 提高效率: 缓冲流通过减少磁盘访问次数,可以显著提高读写的效率,尤其是在处理大量数据时。
- 通常连接其他流: 缓冲流通常会连接在其他输入和输出流的基础上,例如
FileInputStream
和FileOutputStream
,以提供更高效的读写操作。 - flush()方法: 缓冲流中的缓冲区可能没有被完全填满,当需要立即将缓冲区的数据写入底层流时,可以调用
flush()
方法。这样可以确保所有缓冲区中的数据被刷新到底层流中,而不需要等到缓冲区满了。
使用缓冲流可以避免频繁地与磁盘进行交互,提高了读写操作的效率。通常,在处理文件时,建议使用缓冲流来提高程序的性能。
实验:
创建一个存储空间,其最大容量为 MAX_STORE_SIZE(例如,500KB 的随机字节)。将这些字节逐个写入文件;逐个从文件中读取这些字节;对时间效率进行基准测试。
import java.io.*; import java.util.ArrayList; /** * Buffertest 类用于测试不同文件读写方法的性能,包括使用普通的 FileInputStream 和 FileOutputStream, * 以及使用 BufferedInputStream 和 BufferedOutputStream 进行缓冲读写。 */ public class Buffertest { private ArrayList<Integer> intStoreSource; // 存储随机整数的列表(源数据) private ArrayList<Integer> intStoreTarget; // 存储从文件读取的整数的列表 private final int MAX = 500000; // 存储整数的最大数量 private File testFile; // 测试文件的 File 对象 /** * 无参数的构造方法,用于创建 Buffertest 对象。 */ public Buffertest() { } /** * 带参数的构造方法,用于创建 Buffertest 对象,并初始化测试数据。 * * @param file 用于测试的文件 */ public Buffertest(File file) { intStoreSource = new ArrayList<Integer>(); intStoreTarget = new ArrayList<Integer>(); for (int i = 0; i <= MAX; i++) { this.initialSource(); } this.testFile = file; } /** * 生成随机整数的辅助方法。 * * @return 生成的随机整数 */ public int randomInt() { return (int) (Math.random() * 255); } /** * 将生成的随机整数添加到 intStoreSource 列表中。 */ public void initialSource() { intStoreSource.add(randomInt()); } /** * 使用 FileInputStream 读取文件中的整数,并存储到 intStoreTarget 列表中。 * * @throws IOException 如果读取文件时发生 I/O 异常 */ public void useFileInput() throws IOException { FileInputStream fis = new FileInputStream(testFile); int intValue = fis.read(); while (intValue != -1) { this.intStoreTarget.add(intValue); intValue = fis.read(); } fis.close(); } /** * 使用 FileOutputStream 将 intStoreSource 列表中的整数写入文件。 * * @throws IOException 如果写入文件时发生 I/O 异常 */ public void useFileOutput() throws IOException { FileOutputStream fos = new FileOutputStream(testFile); for (int i = 0; i < this.intStoreSource.size(); i++) { fos.write(intStoreSource.get(i)); } fos.close(); } /** * 使用 BufferedInputStream 读取文件中的整数,并存储到 intStoreTarget 列表中。 * * @throws IOException 如果读取文件时发生 I/O 异常 */ public void useBufInput() throws IOException { BufferedInputStream bis = new BufferedInputStream(new FileInputStream(testFile)); int intValue = bis.read();// 通过 read 方法读取下一个字节,文件指针向前移动 while (intValue != -1) { this.intStoreTarget.add(intValue); intValue = bis.read(); } bis.close(); } /** * 使用 BufferedOutputStream 将 intStoreSource 列表中的整数写入文件。 * * @throws IOException 如果写入文件时发生 I/O 异常 */ public void useBufOutput() throws IOException { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(testFile)); for (int i = 0; i < this.intStoreSource.size(); i++) { bos.write(intStoreSource.get(i)); } bos.close(); } /** * 进行性能测试的方法,分别测试了使用不同流的读写操作所需的时间。 * * @throws IOException 如果读写文件时发生 I/O 异常 */ public void test() throws IOException { System.gc(); long time1 = System.currentTimeMillis(); this.useFileOutput(); long time2 = System.currentTimeMillis(); this.useFileInput(); long time3 = System.currentTimeMillis(); this.intStoreTarget = new ArrayList<Integer>(); System.gc(); long time4 = System.currentTimeMillis(); this.useBufOutput(); long time5 = System.currentTimeMillis(); this.useBufInput(); long time6 = System.currentTimeMillis(); System.out.println("FileOutputStream: " + (time2 - time1) + "\t\t" + "FileInputStream: " + (time3 - time2)); System.out.println("BufferedOutputStream: " + (time5 - time4) + "\t\t" + "BufferedInputStream: " + (time6 - time5)); } /** * 主方法,用于创建 Buffertest 对象并执行测试。 * * @param args 命令行参数 */ public static void main(String[] args) { Buffertest test = new Buffertest(new File("e:/张之恒是傻逼.dat")); try { test.test(); } catch (IOException e) { throw new RuntimeException(e); } } }
随机访问文件
Random Access File(随机访问文件)
java.io.RandomAccessFile
类提供了对文件的随机访问,特别适用于处理固定长度记录的文件。以下是关于 RandomAccessFile
的一些要点:
- 固定长度记录:
RandomAccessFile
适用于处理每个记录长度相同的文件,因此适用于一些需要随机读写记录的场景。 - 定位操作: 使用
seek(long position)
方法可以定位到文件中的指定位置。这样可以直接跳过文件的部分内容,从而实现随机读写。 - 不涉及 InputStream 和 OutputStream:
RandomAccessFile
不继承自 InputStream 或 OutputStream,而是直接实现了 DataInput 和 DataOutput 接口,因此可以直接进行数据的读写,而不需要通过中间流的缓冲。 - 类似 DataInputStream 和 DataOutputStream:
RandomAccessFile
提供了类似于DataInputStream
和DataOutputStream
的方法,可以方便地读写各种基本数据类型。 - 常用于搜索引擎索引的构建: 由于其支持随机访问和记录定长的特性,
RandomAccessFile
常常被用于构建搜索引擎的索引,其中需要高效地读写记录。
使用 RandomAccessFile
可以灵活地操作文件的不同部分,这在某些场景下非常有用,比如需要在文件中查找、修改或追加数据。
良好的编程习惯:
在文件处理中,有一些常见的编程错误和良好的编程习惯需要注意:
常见编程错误:
- 使用
FileOutputStream
写入已存在的文件: 如果使用FileOutputStream
写入一个已存在的文件,该文件的现有内容将被覆盖。 - 路径错误: 在处理文件路径时,要注意反斜杠
\
和双反斜杠\\
的使用,以避免路径错误。
良好的编程习惯:
- 选择
r
模式用于RandomAccessFile
的只读操作: 当使用RandomAccessFile
时,如果只需要执行读取操作,应该选择r
模式,以确保不会意外地修改文件内容。 - 在使用
FileOutputStream
之前判断文件是否存在: 在使用FileOutputStream
写入文件之前,最好先判断文件是否已经存在,以避免覆盖已有文件。 - 尽可能使用缓冲: 在文件读写操作时,尽可能使用缓冲流(如
BufferedInputStream
和BufferedOutputStream
),以提高读写效率。 - 记得关闭流: 在使用完文件流后,始终记得关闭它们以释放资源。可以使用
try-with-resources
语句(Java 7+)来自动关闭流。
这些良好的编程习惯有助于提高代码的可维护性、可读性,并减少潜在的错误。
简介 Java NIO(New I/O)
Java NIO(New I/O)提供了一种更为高效的I/O(输入/输出)方式,旨在提高速度和灵活性。以下是对 Java NIO 的简要介绍:
动机:高速I/O
- Java NIO 的动机之一是通过提供更高效的I/O操作来提高速度,特别是在处理大量数据时。
内存映射文件(Mapped Memory File)
- Java NIO 引入了内存映射文件的概念,允许将文件的一部分或整个文件直接映射到内存中。这种方式可以提高文件的读写性能。
示例:
import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class MappedByteBufferExample { public static void main(String[] args) throws Exception { // 创建一个RandomAccessFile对象,表示打开一个文件 RandomAccessFile file = new RandomAccessFile("example.txt", "rw"); // 获取文件通道 FileChannel channel = file.getChannel(); // 创建一个MappedByteBuffer,将文件的一部分(128M)映射到内存 MappedByteBuffer mappedBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 128 * 1024 * 1024); // 将每个字节设置为字符 'x' 的二进制表示 for (int i = 0; i < mappedBuffer.capacity(); i++) { mappedBuffer.put((byte) 'x'); } // 从文件的中间读取6个字节 for (int i = 65; i < 71; i++) { System.out.print((char) mappedBuffer.get(i)); } // 关闭文件通道 channel.close(); } }
在这个示例中,我们通过 FileChannel.map
方法创建了一个 MappedByteBuffer
,并将文件的前128兆字节映射到内存中。然后,我们将每个字节设置为字符 'x' 的二进制表示。最后,我们从文件的中间读取了6个字节并将其打印出来。这种方式可以有效提高大文件的读写性能。
类似的示例
import java.io.*; import java.nio.*; import java.nio.channels.*; public class LargeMappedFiles { static int length = 1024*1024*1024; // 128 Mb public static void main(String[] args) throws Exception { // 创建一个 RandomAccessFile 对象,表示打开一个文件,并获取其文件通道 MappedByteBuffer out = new RandomAccessFile("e:/test.dat", "rw").getChannel() .map(FileChannel.MapMode.READ_WRITE, 0, length); // 记录写入操作开始时间 long begin = System.currentTimeMillis(); // 将每个字节设置为字符 'x' 的二进制表示 for (int i = 0; i < length; i++) { out.put((byte) 'x');//输出用put,输入用get } // 记录写入操作结束时间 long end = System.currentTimeMillis(); System.out.println("Finished writing using " + (end - begin) + "ms."); // 从文件的中间读取6个字节,并打印出来 for (int i = length / 2; i < length / 2 + 6; i++) { System.out.print((char) out.get(i)); } } }
这个程序的主要功能包括:
- 创建一个大小为128兆字节的文件("d:/test.dat")。
- 使用
MappedByteBuffer
内存映射文件,将文件的内容映射到内存中。 - 将文件中的每个字节都设置为字符 'x' 的二进制表示。
- 记录写入操作的开始和结束时间,并输出写入所花费的时间。
- 从文件的中间位置读取6个字节,并将其打印出来。
此示例演示了内存映射文件的用法,它在处理大文件时可以提供更高的性能。
BenchMark对比
以下是一种可能的方法,用于比较内存映射文件与 DataInputStream、DataOutputStream 和 RandomAccessFile 的性能。
import java.io.*; import java.nio.*; import java.nio.channels.*; public class Benchmark { static int length = 500000;//0x8FFFFFF; // 128 Mb // 基准测试:DataInputStream public static void benchmarkDataInputStream() throws Exception { long begin = System.currentTimeMillis(); DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("e:/test1.dat")))); // 读取数据示例 while (dis.available() > 0) { int data = dis.readInt(); // 在此处处理读取的数据,缺省 //System.out.println(data); } dis.close(); long end = System.currentTimeMillis(); System.out.println("基准测试 DataInputStream: " + (end - begin) + "ms."); } // 基准测试:DataOutputStream public static void benchmarkDataOutputStream() throws Exception { long begin = System.currentTimeMillis(); DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("e:/test1.dat")))); // 写入数据示例 for (int i = 0; i < length; i++) { dos.writeInt(i); } dos.close(); long end = System.currentTimeMillis(); System.out.println("基准测试 DataOutputStream: " + (end - begin) + "ms."); } // 基准测试:RandomAccessFile public static void benchmarkRandomAccessFile() throws Exception { long begin = System.currentTimeMillis(); RandomAccessFile raf = new RandomAccessFile("e:/test1.dat", "rw"); // 读写数据示例,这里的代码其实应该分成“读”和“写”两个函数,但是我有点懒了,将就着看() for (int i = 0; i < length; i++) { raf.writeByte(i); raf.seek(i); // 定位到指定位置读取数据 int data = raf.readByte(); // 在此处处理读取的数据,缺省 } raf.close(); long end = System.currentTimeMillis(); System.out.println("基准测试 RandomAccessFile: " + (end - begin) + "ms."); } // 基准测试:内存映射文件 public static void benchmarkMemoryMappedFile() throws Exception { long begin = System.currentTimeMillis(); MappedByteBuffer mbb = new RandomAccessFile("e:/test1.dat", "rw").getChannel() .map(FileChannel.MapMode.READ_WRITE, 0, length); // 读写数据示例,这里的代码其实应该分成“读”和“写”两个函数,但是我有点懒了,将就着看() for (int i = 0; i < length; i++) { mbb.put((byte) i); mbb.position(i); // 定位到指定位置读取数据 int data = mbb.get(); // 在此处处理读取的数据,缺省 } long end = System.currentTimeMillis(); System.out.println("基准测试 内存映射文件: " + (end - begin) + "ms."); } public static void main(String[] args) { try { benchmarkDataOutputStream(); benchmarkDataInputStream(); benchmarkRandomAccessFile(); benchmarkMemoryMappedFile(); } catch (Exception e) { e.printStackTrace(); } } }
- (可以看出,差距非常大,切记我甚至把读写放进了一个函数里)
本文作者:小黑菌梦不到电子羊
本文链接:https://www.cnblogs.com/xiaoheijun/p/17872288.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界