面试题答案
一键面试文件读取方式
- 分块读取:
- 不要一次性将整个大文件读入内存。使用
BufferedInputStream
和FileInputStream
配合,每次读取固定大小的字节数组。例如:
File file = new File("largeFile.txt"); FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); byte[] buffer = new byte[8192]; // 8KB缓冲区 int bytesRead; while ((bytesRead = bis.read(buffer)) != -1) { // 在这里处理读取到的buffer数据,比如发送到Socket } bis.close(); fis.close();
- 不要一次性将整个大文件读入内存。使用
- 内存映射文件:
- Java NIO提供了内存映射文件的功能,通过
MappedByteBuffer
可以将文件部分或全部映射到内存中。这种方式不会像常规读取那样将整个文件加载到堆内存,从而避免堆内存溢出。例如:
RandomAccessFile raf = new RandomAccessFile("largeFile.txt", "r"); FileChannel fc = raf.getChannel(); MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); // 可以直接操作MappedByteBuffer,如通过Socket发送数据 fc.close(); raf.close();
- Java NIO提供了内存映射文件的功能,通过
缓冲区设置
- 合理设置发送缓冲区:
- 在Socket的
OutputStream
上使用BufferedOutputStream
时,要合理设置缓冲区大小。如果缓冲区设置过小,可能会导致频繁的系统调用,降低传输效率;如果设置过大,可能会占用过多内存。一般来说,8KB到64KB是比较常用的缓冲区大小范围。例如:
Socket socket = new Socket("serverAddress", port); OutputStream os = socket.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os, 16384); // 16KB缓冲区 // 分块读取文件数据写入bos bos.flush(); bos.close(); os.close(); socket.close();
- 在Socket的
- 接收缓冲区设置:
- 在服务端,对于接收数据的
InputStream
,同样要合理设置BufferedInputStream
的缓冲区大小。这可以确保在接收大文件时,能高效地处理数据而不占用过多内存。例如:
ServerSocket serverSocket = new ServerSocket(port); Socket clientSocket = serverSocket.accept(); InputStream is = clientSocket.getInputStream(); BufferedInputStream bis = new BufferedInputStream(is, 32768); // 32KB缓冲区 // 处理接收到的数据,如写入文件 bis.close(); is.close(); clientSocket.close(); serverSocket.close();
- 在服务端,对于接收数据的
其他措施
- 及时释放资源:
- 在文件传输完成后,要及时关闭相关的流和Socket连接,释放资源。例如在发送端:
// 文件发送代码 bos.close(); os.close(); socket.close();
- 在接收端:
// 文件接收代码 bis.close(); is.close(); clientSocket.close(); serverSocket.close();
- 优化传输逻辑:
- 可以采用多线程分块传输的方式,将大文件分成多个部分同时传输,提高传输效率的同时,也能更好地控制内存使用。例如,将文件按一定大小分成N块,启动N个线程分别传输这些块。但要注意线程同步和资源管理,避免出现数据混乱或资源泄漏。