使用缓冲读取器读取没有换行符的文件

3
我正在阅读一个以逗号分隔的文件,当将其拆分为数组时,每行将有10个值。我希望文件有换行符,这样可以清晰地区分每一行。
line = bReader.readLine()

我想要每一行的内容,但是我的文件并没有换行符。相反,在第一组值之后有很多空格(确切地说是465个),然后下一行开始。

因此,我的readLine()代码会一次性读取整个文件,因为没有换行符。请建议如何最有效地解决这种情况。


可以用固定大小的记录来创建文件吗?比如512字节之类的。然后就可以重复读取固定大小的字节缓冲区。 - Joop Eggen
每行有11个用逗号分隔的值,后面跟着465个空格字符。然后是下一组逗号分隔的值。但每行中的字符数可能会有所不同,而值的数量始终为11个(10个逗号)。文件大小也可能会有所不同。 - Shahul Basha
“efficiently”这个词是指最小化代码还是操作性能?后者应该是好的,因为BufferedReader会高效地将文件加载到内存中。 如果您有非常大的文件不想在内存中处理,那么一种有效的方法是每次读取较小的部分到缓冲区中,比如每次几KB。 - Markus Fischer
我所指的高效包括性能方面,并且我不清楚如何解决这个问题。比如,我应该用"\n"替换掉465个空格字符,然后按行读取吗?按512字节读取是否会读取我的第一行?很抱歉我无法理解,但是一个代码示例会有所帮助。 - Shahul Basha
5个回答

1

一种方法是在迭代读取文本之前,用换行符"\n"替换您的文本中的465个空格字符串。


0
我支持Ninan的回答:用换行符替换465个空格,然后运行你之前打算运行的函数。
为了美观和可读性,我建议使用正则表达式模式来代替冗长难懂的 String.replace(" ")
你的代码可以像下面这样,但是将6替换成465:
 // arguments are passed using the text field below this editor
  public static void main(String[] args)
  {
    String content = "DOG,CAT      MOUSE,CHEESE";
    Pattern p = Pattern.compile("[ ]{6}",
            Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
    String newString = p.matcher(content).replaceAll("\n");
    System.out.println(newString); 
  }

是的,这将解决我的问题的第二部分,这意味着我必须将整个文件读入单个字符串,然后执行上述过程。但第一部分是有时它是一个非常大的文件,将整个文件读入单行会导致一些内存问题。 - Shahul Basha

0

我的建议是读取文件f1.txt并将其写入另一个文件f2.txt,通过删除所有空行和空格,然后读取f2.txt,类似于以下内容:

FileReader fr = new FileReader("f1.txt"); 
BufferedReader br = new BufferedReader(fr); 
FileWriter fw = new FileWriter("f2.txt"); 
String line;

 while((line = br.readLine()) != null)
{ 
line = line.trim(); // remove leading and trailing whitespace
if (!line.equals("")) // don't write out blank lines
{
    fw.write(line, 0, line.length());
}

}

然后尝试使用您的代码。


0

你可以创建自己的 FilterInputStreamPushbackInputStream 子类,并将其传递给 InputStreamReader。其中一个重写了 int read() 方法。

这样的类需要一些打字工作,但是这是一个不错的练习。

private static final int NO_CHAR = -2;
private boolean fromCache;
private int cachedSpaces;
private int cachedNonSpaceChar = NO_CHAR;

int read() throws IOException {
    if (fromCache) {
        if (cachecSpaces > 0) ...
        if (cachedNonSpaceChar != NO_CHAR) ...
        ...
    }
    int ch = super.read();
    if (ch != -1) {
        ...
    }
    return ch;
}

这个想法是缓存空格,直到遇到非空格字符,在read()中要么从缓存中获取,返回\n,当不是从缓存中获取时调用super.read(),当遇到空格时递归read


0

我的理解是,您有一个扁平的CSV文件,没有正确的换行符,每行应该有10个值。

更新: 1.(推荐)您可以使用Scanner类和useDelimiter有效地解析csv,假设您正在尝试从一行中存储10个值:

    public static void parseCsvWithScanner() throws IOException {

    Scanner scanner = new Scanner(new File("test.csv"));

    // set your delimiter for scanner, "," for csv
    scanner.useDelimiter(",");

    // storing 10 values as a "line"
    int LINE_LIMIT = 10;

    // implement your own data structure to store each value of CSV
    int[] tempLineArray = new int[LINE_LIMIT];

    int lineBreakCount = 0;

    while(scanner.hasNext()) {

        // trim start and end spaces if there is any
        String temp = scanner.next().trim();
        tempLineArray[lineBreakCount++] = Integer.parseInt(temp);

        if (lineBreakCount == LINE_LIMIT) {

            // replace your own logic for handling the full array
            for(int i=0; i<tempLineArray.length; i++) {
                System.out.print(tempLineArray[i]);
            } // end replace

            // resetting array and counter
            tempLineArray = new int[LINE_LIMIT];
            lineBreakCount = 0;
        }
    }
    scanner.close();
}
  • 或者使用 BufferedReader。 如果存在内存问题,可以通过替换自己的逻辑来避免使用 ArrayList 存储所有值。

    public static void parseCsv() throws IOException {
        BufferedReader br = new BufferedReader(new FileReader(file));
        // 您的分隔符
        char TOKEN = ',';
        // 每个“行”存储 10 个值的要求
        int LINE_LIMIT = 10;
        // 用于从 BufferedReader.read() 中存储 tmp
        int tmp;
        // 行断点计数器
        int lineBreakCount = 0;
        // 数组用于存储 10 个值,假设 CSV 的值为整数
        int[] tempArray = new int[LINE_LIMIT];
        // 将每行的 tempArray 存储到 ArrayList 中
        ArrayList<int[]> lineList = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
    
        while((tmp = br.read()) != -1) {
            if ((char)tmp == TOKEN) {
                if (lineBreakCount == LINE_LIMIT) {
                    // 在此处理当前“行”的逻辑。
                    lineList.add(tempArray);
                    // 新“行”
                    tempArray = new int[LINE_LIMIT];
                    lineBreakCount = 0;
                }
                // 使用空格修剪后从缓冲区存储当前值
                tempArray[lineBreakCount] =
                        Integer.parseInt(sb.toString().trim());
                lineBreakCount++;
                // 清除缓冲区
                sb.delete(0, sb.length());
            }
            else {
                // 如果不是分隔符,则添加来自 BufferedReader 的当前字符
                sb.append((char)tmp);
            }
        }
        br.close();
    }
    

  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接