簡體   English   中英

從 txt 文件中刪除一行后的單詞被讀取

[英]Remove word after line from txt file is read

我有這段代碼用於從文件中讀取行並將其插入 Postgre:

try {
            BufferedReader reader;
            try {
                reader = new BufferedReader(new FileReader(
                        "C:\\in_progress\\test.txt"));
                String line = reader.readLine();
                while (line != null) {
                    System.out.println(line);

                    Thread.sleep(100);
                    Optional<ProcessedWords> isFound = processedWordsService.findByKeyword(line);

                    if(!isFound.isPresent()){
                        ProcessedWords obj = ProcessedWords.builder()
                                .keyword(line)
                                .createdAt(LocalDateTime.now())
                                .build();
                        processedWordsService.save(obj);
                    }

                    // read next line
                    line = reader.readLine();
                }
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

將行插入 SQL 數據庫后,如何從文件中刪除一行?

以供參考

import java.io.*;

public class RemoveLinesFromAfterProcessed {
    public static void main(String[] args) throws Exception {
        String fileName = "TestFile.txt";
        String tempFileName = "tempFile";

        File mainFile = new File(fileName);
        File tempFile = new File(tempFileName);

        try (BufferedReader br = new BufferedReader(new FileReader(mainFile));
             PrintWriter pw = new PrintWriter(new FileWriter(tempFile))
        ) {
            String line;
            while ((line = br.readLine()) != null) {
                if (toProcess(line)) {  // #1
                    // process the code and add it to DB
                    // ignore the line (i.e, not add to temp file)
                } else {
                    // add to temp file.
                    pw.write(line + "\n");  // #2
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // delete the old file
        boolean hasDeleted = mainFile.delete();  // #3
        if (!hasDeleted) {
            throw new Exception("Can't delete file!");
        }
        boolean hasRenamed = tempFile.renameTo(mainFile);  // #4
        if (!hasRenamed) {
            throw new Exception("Can't rename file!");
        }

        System.out.println("Done!");
    }

    private static boolean toProcess(String line) {
        // any condition
        // sample condition for example
        return line.contains("aa");
    }
}

閱讀文件。
1:決定是刪除還是保留該行的條件。
2:將不想刪除的行寫入臨時文件。
3:刪除原文件。
4:將臨時文件重命名為原始文件名。

基本思想與@Shiva Rahul 在回答中所說的相同。


但是另一種方法是,將所有要刪除的行號存儲在一個list 在您擁有要刪除的所有必需的行號后,您可以使用LineNumberReader檢查和復制您的主文件。

大多數情況下,我在批量插入中使用了這種技術,我不確定有多少行可能有一個特定的文件,加上在刪除行之前必須進行大量處理。 它可能不適合您的情況,如果有人碰到此線程,請在此處發布建議。

private void deleteLines(String inputFilePath,String outputDirectory,List<Integer> lineNumbers) throws IOException{
    File tempFile = new File("temp.txt");
    File inputFile = new File(inputFilePath);

    // using LineNumberReader we can fetch the line numbers of each line
    LineNumberReader lineReader = new LineNumberReader(new FileReader(inputFile));

    //writter for writing the lines into new file
    BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(tempFile));
    String currentLine;
    while((currentLine = lineReader.readLine()) != null){

        //if current line number is present in removeList then put empty line in new file
        if(lineNumbers.contains(lineReader.getLineNumber())){
            currentLine="";
        }
        bufferedWriter.write(currentLine + System.getProperty("line.separator"));
    }
    //closing statements
    bufferedWriter.close();
    lineReader.close();

    //delete the main file and rename the tempfile to original file Name
    boolean delete = inputFile.delete();
    //boolean b = tempFile.renameTo(inputFile); // use this to save the temp file in same directory;
    boolean b = tempFile.renameTo(new File(outputDirectory+inputFile.getName()));
}

要使用此功能,您只需收集所有需要的行號。 inputFilePath是源文件的路徑,而outputDirectory是我要在處理后存儲文件的位置。

當前代碼的問題:

  • 堅持單一職責原則 你的代碼做了太多的事情:從文件中讀取,執行findByKeyword()調用,准備數據並將其分發到數據庫中。 它幾乎無法徹底測試,並且很難維護
  • 在任何情況下,始終使用try-with-recourses來關閉您的資源。
  • 不要捕獲一般的Exception類型 - 您的代碼應該只捕獲 thou 異常,這些異常或多或少是預期的,並且對於如何處理它們有明確的方案。 但不要捕獲所有異常。

將行插入 SQL 數據庫后,如何從文件刪除一行

從字面上看,不可能從文件中刪除一行。 您可以覆蓋文件的內容或將其替換為另一個文件。

我的建議是將數據歸檔到內存中,對其進行處理,然后將應該保留的行寫入同一個文件中(即覆蓋文件內容)。

您可以爭辯說該文件很大,將其轉儲到內存中會導致OutOfMemoryError 您想從文件中讀取一行,以某種方式對其進行處理,然后將處理后的數據存儲到數據庫中,然后將該行寫入文件中......這樣一切都逐行完成,所有操作一次完成單行,因此所有代碼都擠在一種方法中。 我希望情況並非如此,否則這是一個明顯的XY-problem

首先,文件系統不是一種可靠的數據存儲方式,而且速度不是很快。 如果文件很大,那么讀取和寫入它將花費大量時間,並且只是為了使用少量信息而完成它,那么這種方法是錯誤的 - 這些信息應該以不同的方式存儲和構造(即考慮放入數據庫),以便可以檢索所需的數據,並且刪除不再需要的條目不會有問題。

但是如果文件很精簡,並且不包含關鍵數據。 那么它完全沒問題,我會繼續假設它是這種情況。

總體方法是根據文件內容生成一個映射Map<String, Optional<ProcessedWords>> ,處理非空的可選項並准備一個行列表來覆蓋之前的文件內容。

下面的代碼基於 NIO2 文件系統 API。

public void readProcessAndRemove(ProcessedWordsService service, Path path) {
    
    Map<String, Optional<ProcessedWords>> result;
    
    try (var lines = Files.lines(path)) {
        result = processLines(service, lines);
    } catch (IOException e) {
        result = Collections.emptyMap();
        logger.log();
        e.printStackTrace();
    }
    
    List<String> linesToRetain = prepareAndSave(service, result);
    writeToFile(linesToRetain, path);
}

處理來自文件的行流返回Files.lines()

private static Map<String, Optional<ProcessedWords>> processLines(ProcessedWordsService service,
                                                                  Stream<String> lines) {
    return lines.collect(Collectors.toMap(
        Function.identity(),
        service::findByKeyword
    ));
}

保存findByKeyword()返回空選項的單詞:

private static List<String> prepareAndSave(ProcessedWordsService service,
                                           Map<String, Optional<ProcessedWords>> wordByLine) {
    wordByLine.forEach((k, v) -> {
        if (v.isEmpty()) saveWord(service, k);
    });
    
    return getLinesToRetain(wordByLine);
}

private static void saveWord(ProcessedWordsService service, String line) {
    
    ProcessedWords obj = ProcessedWords.builder()
        .keyword(line)
        .createdAt(LocalDateTime.now())
        .build();
    service.save(obj);
}

生成要保留的行列表:

private static List<String> getLinesToRetain(Map<String, Optional<ProcessedWords>> wordByLine) {
    
    return wordByLine.entrySet().stream()
        .filter(entry -> entry.getValue().isPresent())
        .map(Map.Entry::getKey)
        .collect(Collectors.toList());
}

使用Files.write()覆蓋文件內容。 注意:由於沒有為可變參數OpenOption提供任何參數,因此該調用將被視為存在CREATETRUNCATE_EXISTINGWRITE選項。

private static void writeToFile(List<String> lines, Path path) {
    try {
        Files.write(path, lines);
    } catch (IOException e) {
        logger.log();
        e.printStackTrace();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM