You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何按行读取文本文件并指定字节偏移量与限制(不加载全文件)

Java按行读取指定字节范围的文本文件

你需要读取文件的0-9500字节(排除末尾500字节的签名),同时按行处理且不加载整个文件到内存,以下是两种可靠的实现方式:

方法一:使用RandomAccessFile(传统IO)

RandomAccessFile支持直接定位到指定偏移量,同时可按行读取,只需控制累计读取字节数不超过9500即可避免读到签名部分。

import java.io.RandomAccessFile;
import java.io.IOException;

public class LineReaderWithOffset {
    public static void main(String[] args) {
        final long START_OFFSET = 0;
        final long MAX_READ_BYTES = 9500;
        String filePath = "your-target-file.txt";

        try (RandomAccessFile raf = new RandomAccessFile(filePath, "r")) {
            raf.seek(START_OFFSET); // 定位到起始偏移位置
            long totalBytesRead = 0;
            String line;
            long lastPos = START_OFFSET;

            while (totalBytesRead < MAX_READ_BYTES && (line = raf.readLine()) != null) {
                long currentPos = raf.getFilePointer();
                // 计算当前行的实际字节数(包含换行符)
                long lineByteCount = currentPos - lastPos;
                totalBytesRead += lineByteCount;

                // 处理当前行(若文件是UTF-8编码,需转码避免乱码)
                String decodedLine = new String(line.getBytes("ISO-8859-1"), "UTF-8");
                System.out.println(decodedLine);

                // 检查是否即将超出读取限制,提前终止
                if (totalBytesRead >= MAX_READ_BYTES) {
                    break;
                }
                lastPos = currentPos;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

方法一注意事项

  • raf.readLine()默认使用系统编码,若文件为UTF-8等非默认编码,必须手动转码,否则会出现乱码。
  • 通过文件指针位置差计算行字节数,能准确统计累计读取量,避免读到末尾的签名内容。

方法二:使用FileChannel + CharsetDecoder(NIO高效实现)

NIO的FileChannel可精准控制读取的字节范围,结合CharsetDecoder能正确处理多字节编码(如UTF-8),同时用小缓冲区降低内存占用。

import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.CharBuffer;

public class NIOByteRangeLineReader {
    public static void main(String[] args) {
        final long START_OFFSET = 0;
        final long MAX_READ_BYTES = 9500;
        String filePath = "your-target-file.txt";
        Charset charset = Charset.forName("UTF-8"); // 根据文件实际编码调整
        CharsetDecoder decoder = charset.newDecoder();

        try (FileInputStream fis = new FileInputStream(filePath);
             FileChannel channel = fis.getChannel()) {

            ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 1KB小缓冲区,内存占用极低
            CharBuffer charBuffer = CharBuffer.allocate(1024);
            long totalBytesRead = 0;
            long currentPosition = START_OFFSET;
            StringBuilder lineBuilder = new StringBuilder();

            while (totalBytesRead < MAX_READ_BYTES) {
                // 计算本次可读取的最大字节数,避免超出限制
                long bytesToRead = Math.min(MAX_READ_BYTES - totalBytesRead, byteBuffer.capacity());
                int readBytes = channel.read(byteBuffer, currentPosition);
                if (readBytes == -1) break;

                totalBytesRead += readBytes;
                currentPosition += readBytes;
                byteBuffer.flip();

                // 解码字节为字符,处理可能的跨缓冲区字符
                CoderResult result = decoder.decode(byteBuffer, charBuffer, totalBytesRead >= MAX_READ_BYTES);
                charBuffer.flip();

                // 解析每行内容
                while (charBuffer.hasRemaining()) {
                    char c = charBuffer.get();
                    if (c == '\n') {
                        // 处理Windows下的\r换行符
                        String line = lineBuilder.toString().replace("\r", "");
                        System.out.println(line);
                        lineBuilder.setLength(0);
                    } else {
                        lineBuilder.append(c);
                    }
                }

                charBuffer.compact();
                byteBuffer.compact();
            }

            // 处理文件末尾无换行符的最后一行
            if (lineBuilder.length() > 0) {
                System.out.println(lineBuilder.toString().replace("\r", ""));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

方法二优势

  • 精准控制读取范围,绝对不会读取到末尾的500字节签名。
  • 小缓冲区设计,内存占用远低于加载整个文件的方式。
  • 原生支持多字节编码解码,彻底避免乱码问题。

内容的提问来源于stack exchange,提问作者KUL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 00:30:12