根据不同的标题从文件中读取并写入另一个文件

read from file and write to another files according to different titles

我有一个关于 java 读取和写入文件的问题。在我要阅读的文件中,有四个标题“this_is_table_med”、“this_is_table_nts”、“this_is_table_lehramt”、“this_is_table_allg”,后面是它们的内容。如图: 我想将它们分成 4 个 table,因为实际上有 4 个 table 带有标题和内容。最后,我只得到“this_is_table_med”和“this_is_table_lehramt”的 table,不是全部 4 个 table,有人可以帮忙吗? 我的代码是这样的:

File file = new File(inputFileName);
BufferedReader br = new BufferedReader(new FileReader(file));
String st;
while ((st = br.readLine()) != null) {
    if (st != null && st.equals("this_is_table_nts")) {
        File file_nts = new File(outputPath + "_nts_dropOut.csv");
        FileOutputStream fo_nts = new FileOutputStream(file_nts);
        BufferedWriter writer_nts = new BufferedWriter(new OutputStreamWriter(fo_nts));
        st = br.readLine();
        while (st != null && !st.contains("this_is_table_")) {

            writer_nts.write(st);
            writer_nts.newLine();

            st = br.readLine();

        }
        writer_nts.flush();
        writer_nts.close();

    } else if (st != null && st.equals("this_is_table_med")) {
        System.out.println("  " + st.toString());
        File file_medizin = new File(outputPath + "_medizin_dropOut.csv");
        FileOutputStream fo_medizin = new FileOutputStream(file_medizin);
        BufferedWriter writer_medizin = new BufferedWriter(new OutputStreamWriter(fo_medizin));
        st = br.readLine();
        while (st != null && !st.contains("this_is_table_")) {
            writer_medizin.write(st);
            writer_medizin.newLine();

            st = br.readLine();
        }
        writer_medizin.flush();
        writer_medizin.close();

    } else if (st != null && st.equals("this_is_table_allg")) {
        System.out.println("  " + st.toString());
        File file_allg = new File(outputPath + "_allg_dropOut.csv");
        FileOutputStream fo_allg = new FileOutputStream(file_allg);
        BufferedWriter writer_allg = new BufferedWriter(new OutputStreamWriter(fo_allg));
        st = br.readLine();
        while (st != null && !st.contains("this_is_table_")) {

            writer_allg.write(st);
            writer_allg.newLine();
            st = br.readLine();

        }
        writer_allg.flush();
        writer_allg.close();


    } else if (st != null && st.equals("this_is_table_lehramt")) {
        System.out.println("  " + st.toString());
        File file_lehramt = new File(outputPath + "_lehramt_dropOut.csv");
        FileOutputStream fo_lehramt = new FileOutputStream(file_lehramt);
        BufferedWriter writer_lehramt = new BufferedWriter(new OutputStreamWriter(fo_lehramt));
        st = br.readLine();
        while (st != null && !st.contains("this_is_table_")) {

            writer_lehramt.write(st);
            writer_lehramt.newLine();
            st = br.readLine();

        }
        writer_lehramt.flush();
        writer_lehramt.close();

    }
    br.close();
}

更新:我认为它跳过 nts 和 allg 的原因是:在 med 的 if 循环中的 while-loop 之后(else if(st!=null&&st.equals("this_is_table_medizin")) "st"等于"this_is_table_nts"。下一步就是外while-loop"st"就是"this_is_table_nts"的下一行,我需要的是让 st="this_is_table_nts" 进入 nts.

的 if 循环

几个问题

  1. 您一次从文件中读取多行。单独留下 while 循环。这样,st = br.readLine() 永远不会为 null,因此您无需检查它

  2. st 只会等于 table 名字几次,所以你不应该在循环中每次都检查它

以下代码未经测试,但显示了总体思路

  • 在“this_is_table”行和没有的行之间分支代码。在读取数据时使用列表保存数据,而不是立即写入文件
  • 当您找到 new "this_is_table" 行时,然后将所有先前的行(列表)保存到文件中
  File file = new File(inputFileName);
  BufferedReader br = new BufferedReader(new FileReader(file));
  String tableName = null;
  String lastTable = null;
  List<String> tableData = new ArrayList<>();

  String st;
  while ((st = br.readLine()) != null) {
      if (st.startsWith("this_is_table_") {  // found start of a table
           // if previous table is known, then save it, e.g. write to a file here
           // condition needed for first table in file
           if (lastTable != null) {           
               String outputFile = tableName.substring("this_is_table".length()) + "_dropOut.csv";
               File out = new File(outputPath, outputFile);
               try(PrintStream ps = new PrintStream(out)) {
                   for (String line : tableData) {
                     ps.println(line);
                   }
               } catch (Exception e) { System.err.println(e); }
               
               // start collecting data for a new table
               tableData = new ArrayList<>();
               lastTable = tableName;
           }

           tableName = st;
      } else {
          if (tableName != null) {
              // currently reading data for 'tableName'
              tableData.add(st);
          }
      }
  }

如果您使用的是 java 8 或更高版本(我强烈认为您是),并且这里的任务并不是要让您处理 BufferedReader & BufferedWriter,那么我会推荐一个不同的方法,它使用 Streamsjava.nio.Files。通过这种方式,您可以轻松调用读写方法,而只需担心行的分组。由于流,分组也更容易。为此,我使用 AtomicInteger,只要一行以 "this_is_table".

开头,我就会增加它

假设您的输入文件类似于:

this_is_table_med 
V7_1,0.0,0.0,13.79
V7_TE,0.0,0.0,100
this_is_table_nts 
V8_1,0.0,0.0,13.79
V8_1,0.0,0.0,100
this_is_table_lehramt 
V38_1,0.0,0.0,100
V38_TE,0.0,0.0,100
this_is_table_allg
V8_2,0.0,0.0,13.79
V8_2,0.0,0.0,13.79

并且位于 fileName 以下代码段将在 outputPath目录

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Example {

    public static void main(String[] args) {

        AtomicInteger counter = new AtomicInteger();
        String fileName = "C:\Users\Miaomiao\Documents\mydata.csv"; 
        String outputPath = "C:\Users\Miaomiao\Documents\dir1\";
        String suffix = "_dropOut.csv";

        try (Stream<String> stream = Files.lines(Paths.get(fileName))) {

            stream.collect(
                    Collectors.groupingBy( line -> isStartOfNewTable(line)? 
                                                   counter.incrementAndGet(): 
                                                   counter.get()))
                    .values().forEach(list -> {
                        String table = list.get(0); 
                        Path path = Paths.get(outputPath + 
                                              table.substring(table.lastIndexOf('_') + 1) +
                                              suffix);
                        try {
                            Files.write(path, list, StandardCharsets.UTF_8);
                        } catch (IOException ex) {
                             ex.printStackTrace();
                        }
                    });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static boolean isStartOfNewTable (String str){
        return str.startsWith("this_is_table");
    }
}