【问题标题】:Reading a File without line breaks using Buffered reader使用缓冲阅读器读取没有换行符的文件
【发布时间】:2019-07-04 19:02:12
【问题描述】:

我正在读取一个带有逗号分隔值的文件,当它拆分为一个数组时,每行将有 10 个值。我希望文件有换行符,以便

line = bReader.readLine()

会给我每一行。但是我的文件没有换行符。相反,在第一组值之后有很多空格(准确地说是 465),然后下一行开始。

所以我上面的 readLine() 代码是一次性读取整个文件,因为没有换行符。请建议如何最好地有效地处理这种情况。

【问题讨论】:

  • 可以是固定大小记录的文件吗?可能是 512 字节左右。然后可以重复读取固定大小的字节缓冲区。
  • 每行有 11 个值,以逗号分隔。后跟 465 个空格字符。然后是下一组逗号分隔值。但是每行中的字符数可能会有所不同,但它始终是 11 个值(10 个逗号)。文件大小也可能有所不同。
  • “高效”是什么意思?在最少的代码或操作性能的意义上?后者应该很好,因为 BufferedReader 会有效地将文件加载到内存中。如果您不想在内存中处理非常大的文件,那么一种有效的方法是将较小的部分读入缓冲区,例如一次几 kB。
  • 高效是指性能方面的,我也不清楚如何解决这个问题。就像我应该用“\ n”替换465个空格字符然后逐行读取?读取 512 字节会读取我的第一行吗?抱歉,我无法掌握,但代码示例会有所帮助

标签: java performance file bufferedreader


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我赞同尼南的回答:用换行符替换 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); 
      }
    

    【讨论】:

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

    我的建议是读取文件 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());
    }
    

    }

    然后尝试使用您的代码。

    【讨论】:

      【解决方案4】:

      您可以创建自己的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

      【讨论】:

        【解决方案5】:

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

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

            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();
        }
        
        1. 或者使用 BufferedReader。 如果通过替换您自己的逻辑存在内存问题,您可能不需要 ArrayList 来存储所有值。

          public static void parseCsv() throws IOException {
              BufferedReader br = new BufferedReader(new FileReader(file));
              // your delimiter
              char TOKEN = ',';
              // your requirement of storing 10 values for each "line"
              int LINE_LIMIT = 10;
              // tmp for storing from BufferedReader.read()
              int tmp;
              // a counter for line break
              int lineBreakCount = 0;
              // array for storing 10 values, assuming the values of CSV are integers
              int[] tempArray = new int[LINE_LIMIT];
              // storing tempArray of each line to ArrayList
              ArrayList<int[]> lineList = new ArrayList<>();
              StringBuilder sb = new StringBuilder();
          
              while((tmp = br.read()) != -1) {
                  if ((char)tmp == TOKEN) {
                      if (lineBreakCount == LINE_LIMIT) {
                          // your logic to handle the current "line" here.
                          lineList.add(tempArray);
                          // new "line"
                          tempArray = new int[LINE_LIMIT];
                          lineBreakCount = 0;
                      }
                      // storing current value from buffer with trim of spaces
                      tempArray[lineBreakCount] =
                              Integer.parseInt(sb.toString().trim());
                      lineBreakCount++;
                      // clear the buffer
                      sb.delete(0, sb.length());
                  }
                  else {
                      // add current char from BufferedReader if not delimiter
                      sb.append((char)tmp);
                  }
              }
              br.close();
          }
          

        【讨论】:

          猜你喜欢
          • 2021-06-30
          • 1970-01-01
          • 2015-11-19
          • 1970-01-01
          • 2015-08-30
          • 1970-01-01
          • 2016-01-23
          • 2013-04-17
          • 2023-03-28
          相关资源
          最近更新 更多