development

파일에서 줄을 찾아 제거

big-blog 2020. 12. 10. 20:49
반응형

파일에서 줄을 찾아 제거


파일에서 한 줄을 찾고 해당 줄 (내용이 아니라 줄)을 제거하지만 찾을 수없는 작은 코드 조각을 찾고 있습니다. 예를 들어 다음 파일에 있습니다.

myFile.txt :

aaa
bbb
ccc
ddd

다음과 같은 기능이 필요합니다.을 public void removeLine(String lineContent)통과 removeLine("bbb")하면 다음과 같은 파일이 생성됩니다.

myFile.txt :

aaa
ccc
ddd

이 솔루션은 최적이거나 예쁘지 않을 수 있지만 작동합니다. 입력 파일을 한 줄씩 읽고 각 줄을 임시 출력 파일에 씁니다. 찾고있는 내용과 일치하는 줄을 발견 할 때마다 해당 줄을 작성하지 않습니다. 그런 다음 출력 파일의 이름을 바꿉니다. 예제에서 오류 처리, 읽기 / 쓰기 닫기 등을 생략했습니다. 또한 찾고있는 줄에 선행 또는 후행 공백이 없다고 가정합니다. 일치하는 항목을 찾을 수 있도록 필요에 따라 trim () 주위의 코드를 변경하십시오.

File inputFile = new File("myFile.txt");
File tempFile = new File("myTempFile.txt");

BufferedReader reader = new BufferedReader(new FileReader(inputFile));
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));

String lineToRemove = "bbb";
String currentLine;

while((currentLine = reader.readLine()) != null) {
    // trim newline when comparing with lineToRemove
    String trimmedLine = currentLine.trim();
    if(trimmedLine.equals(lineToRemove)) continue;
    writer.write(currentLine + System.getProperty("line.separator"));
}
writer.close(); 
reader.close(); 
boolean successful = tempFile.renameTo(inputFile);

    public void removeLineFromFile(String file, String lineToRemove) {

    try {

      File inFile = new File(file);

      if (!inFile.isFile()) {
        System.out.println("Parameter is not an existing file");
        return;
      }

      //Construct the new file that will later be renamed to the original filename.
      File tempFile = new File(inFile.getAbsolutePath() + ".tmp");

      BufferedReader br = new BufferedReader(new FileReader(file));
      PrintWriter pw = new PrintWriter(new FileWriter(tempFile));

      String line = null;

      //Read from the original file and write to the new
      //unless content matches data to be removed.
      while ((line = br.readLine()) != null) {

        if (!line.trim().equals(lineToRemove)) {

          pw.println(line);
          pw.flush();
        }
      }
      pw.close();
      br.close();

      //Delete the original file
      if (!inFile.delete()) {
        System.out.println("Could not delete file");
        return;
      }

      //Rename the new file to the filename the original file had.
      if (!tempFile.renameTo(inFile))
        System.out.println("Could not rename file");

    }
    catch (FileNotFoundException ex) {
      ex.printStackTrace();
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }
  }

이것은 인터넷에서 찾았습니다.


다음과 같은 작업을 원합니다.

  • 읽기 위해 이전 파일을 엽니 다.
  • 쓰기를 위해 새 (임시) 파일 열기
  • 이전 파일의 행을 반복합니다 (아마 BufferedReader 사용 ).
    • 각 줄에 대해 제거하려는 항목과 일치하는지 확인하십시오.
    • 일치하면 아무것도하지 마십시오
    • 일치하지 않으면 임시 파일에 쓰십시오.
  • 완료되면 두 파일을 모두 닫습니다.
  • 이전 파일 삭제
  • 임시 파일의 이름을 원본 파일의 이름으로 바꿉니다.

(실제 코드를 작성하지는 않겠습니다. 숙제처럼 보이지만 문제가있는 특정 부분에 대해 다른 질문을 자유롭게 게시 할 수 있습니다.)


Apache commons-io 및 Java 8을 사용하면

 List<String> lines = FileUtils.readLines(file);
 List<String> updatedLines = lines.stream().filter(s -> !s.contains(searchString)).collect(Collectors.toList());
 FileUtils.writeLines(file, updatedLines, false);

따라서 누군가가 텍스트를 필터링하고 싶다는 말을들을 때마다 즉시 Streams 로 이동하려고합니다 (주로 filter필요한대로 정확히 필터링 하는 메서드가 있기 때문입니다 ). 또 다른 대답 Stream은 Apache commons-io 라이브러리에서 s를 사용하는 것에 대해 언급 하지만 표준 Java 8에서 이것이 어떻게 수행되는지 보여줄 가치가 있다고 생각했습니다. 가장 간단한 형식은 다음과 같습니다.

public void removeLine(String lineContent) throws IOException
{
    File file = new File("myFile.txt");
    List<String> out = Files.lines(file.toPath())
                        .filter(line -> !line.contains(lineContent))
                        .collect(Collectors.toList());
    Files.write(file.toPath(), out, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
}

설명 할 내용이 너무 많지 않다고 생각합니다. 기본적으로 파일 줄을 Files.lines가져오고 원하지 않는 줄을 제거한 다음 새 파일의 모든 줄을 . 그런 다음 추가 옵션을 사용하여 기존 파일 위에 목록을 작성하여 파일 의 이전 내용을 대체합니다.Stream<String>filtercollectListFiles.writeTRUNCATE

물론이 방법은 모든 줄 List이 다시 쓰여지기 전에 모두 저장되므로 메모리에 모든 줄을로드하는 단점이 있습니다. 저장하지 않고 간단하게 수정하려면 OutputStream다음과 같이 스트림을 통과 할 때 파일에 각 새 줄을 작성 하는 데 어떤 형식을 사용해야 합니다.

public void removeLine(String lineContent) throws IOException
{
    File file = new File("myFile.txt");
    File temp = new File("_temp_");
    PrintWriter out = new PrintWriter(new FileWriter(temp));
    Files.lines(file.toPath())
        .filter(line -> !line.contains(lineContent))
        .forEach(out::println);
    out.flush();
    out.close();
    temp.renameTo(file);
}

이 예에서는 많이 변경되지 않았습니다. 기본적으로 collect파일 내용을 메모리에 모으는 데 사용 하는 대신,를 forEach통과하는 각 줄 filter이으로 전송되어 PrintWriter파일에 즉시 기록되고 저장되지 않도록 사용합니다. 임시 파일에 저장해야합니다. 기존 파일을 읽는 동안 동시에 기존 파일을 덮어 쓸 수 없기 때문에 마지막에 임시 파일의 이름을 변경하여 기존 파일을 대체합니다.


여기 있습니다. 이 솔루션은를 사용 하여 바꾸려 DataInputStream는 문자열의 위치를 ​​검색하고를 사용하여 FileChannel정확한 위치에서 텍스트를 바꿉니다. 찾은 문자열의 첫 번째 발생 만 대체합니다. 이 솔루션 은 전체 파일 (RAM 또는 임시 파일) 의 복사본을 어딘가에 저장하지 않고 찾은 파일의 일부만 편집합니다.

public static long scanForString(String text, File file) throws IOException {
    if (text.isEmpty())
        return file.exists() ? 0 : -1;
    // First of all, get a byte array off of this string:
    byte[] bytes = text.getBytes(/* StandardCharsets.your_charset */);

    // Next, search the file for the byte array.
    try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {

        List<Integer> matches = new LinkedList<>();

        for (long pos = 0; pos < file.length(); pos++) {
            byte bite = dis.readByte();

            for (int i = 0; i < matches.size(); i++) {
                Integer m = matches.get(i);
                if (bytes[m] != bite)
                    matches.remove(i--);
                else if (++m == bytes.length)
                    return pos - m + 1;
                else
                    matches.set(i, m);
            }

            if (bytes[0] == bite)
                matches.add(1);
        }
    }
    return -1;
}

public static void replaceText(String text, String replacement, File file) throws IOException {
    // Open a FileChannel with writing ability. You don't really need the read
    // ability for this specific case, but there it is in case you need it for
    // something else.
    try (FileChannel channel = FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.READ)) {
        long scanForString = scanForString(text, file);
        if (scanForString == -1) {
            System.out.println("String not found.");
            return;
        }
        channel.position(scanForString);
        channel.write(ByteBuffer.wrap(replacement.getBytes(/* StandardCharsets.your_charset */)));
    }
}

입력: ABCDEFGHIJKLMNOPQRSTUVWXYZ

메서드 호출 :

replaceText("QRS", "000", new File("path/to/file");

결과 파일 : ABCDEFGHIJKLMNOP000TUVWXYZ


    public static void deleteLine() throws IOException {
        RandomAccessFile file = new RandomAccessFile("me.txt", "rw");
        String delete;
        String task="";
        byte []tasking;
        while ((delete = file.readLine()) != null) {
            if (delete.startsWith("BAD")) {
                continue;
            }
            task+=delete+"\n";
        }
        System.out.println(task);
        BufferedWriter writer = new BufferedWriter(new FileWriter("me.txt"));
        writer.write(task);
        file.close();
        writer.close();
    }

여기에 완전한 클래스가 있습니다. 아래 파일에서 "somelocation"은 파일의 실제 경로를 나타냅니다.

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;



public class FileProcess
{


    public static void main(String[] args) throws IOException
    {
        File inputFile = new File("C://somelocation//Demographics.txt");
        File tempFile = new File("C://somelocation//Demographics_report.txt");

        BufferedReader reader = new BufferedReader(new FileReader(inputFile));
        BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));

        String currentLine;

        while((currentLine = reader.readLine()) != null) {
            if(null!=currentLine && !currentLine.equalsIgnoreCase("BBB")){
                writer.write(currentLine + System.getProperty("line.separator"));
            }
        }
        writer.close(); 
        reader.close(); 
        boolean successful = tempFile.renameTo(inputFile);
        System.out.println(successful);
    }

}

public static void deleteLine(String line, String filePath) {

    File file = new File(filePath);

    File file2 = new File(file.getParent() + "\\temp" + file.getName());
    PrintWriter pw = null;
    Scanner read = null;

    FileInputStream fis = null;
    FileOutputStream fos = null;
    FileChannel src = null;
    FileChannel dest = null;

    try {


        pw = new PrintWriter(file2);
        read = new Scanner(file);

        while (read.hasNextLine()) {

            String currline = read.nextLine();

            if (line.equalsIgnoreCase(currline)) {
                continue;
            } else {
                pw.println(currline);
            }
        }

        pw.flush();

        fis = new FileInputStream(file2);
        src = fis.getChannel();
        fos = new FileOutputStream(file);
        dest = fos.getChannel();

        dest.transferFrom(src, 0, src.size());


    } catch (IOException e) {
        e.printStackTrace();
    } finally {     
        pw.close();
        read.close();

        try {
            fis.close();
            fos.close();
            src.close();
            dest.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (file2.delete()) {
            System.out.println("File is deleted");
        } else {
            System.out.println("Error occured! File: " + file2.getName() + " is not deleted!");
        }
    }

}

package com.ncs.cache;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.FileWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;

public class FileUtil {

    public void removeLineFromFile(String file, String lineToRemove) {

        try {

            File inFile = new File(file);

            if (!inFile.isFile()) {
                System.out.println("Parameter is not an existing file");
                return;
            }

            // Construct the new file that will later be renamed to the original
            // filename.
            File tempFile = new File(inFile.getAbsolutePath() + ".tmp");

            BufferedReader br = new BufferedReader(new FileReader(file));
            PrintWriter pw = new PrintWriter(new FileWriter(tempFile));

            String line = null;

            // Read from the original file and write to the new
            // unless content matches data to be removed.
            while ((line = br.readLine()) != null) {

                if (!line.trim().equals(lineToRemove)) {

                    pw.println(line);
                    pw.flush();
                }
            }
            pw.close();
            br.close();

            // Delete the original file
            if (!inFile.delete()) {
                System.out.println("Could not delete file");
                return;
            }

            // Rename the new file to the filename the original file had.
            if (!tempFile.renameTo(inFile))
                System.out.println("Could not rename file");

        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        FileUtil util = new FileUtil();
        util.removeLineFromFile("test.txt", "bbbbb");
    }
}

소스 : http://www.javadb.com/remove-a-line-from-a-text-file/


이 솔루션을 사용하려면 Apache Commons IO 라이브러리 를 빌드 경로에 추가해야합니다. 전체 파일을 읽고 각 줄을 다시 쓰는 방식으로 작동하지만 검색어가 포함되지 않은 경우에만 가능합니다.

public static void removeLineFromFile(File targetFile, String searchTerm)
        throws IOException
{
    StringBuffer fileContents = new StringBuffer(
            FileUtils.readFileToString(targetFile));
    String[] fileContentLines = fileContents.toString().split(
            System.lineSeparator());

    emptyFile(targetFile);
    fileContents = new StringBuffer();

    for (int fileContentLinesIndex = 0; fileContentLinesIndex < fileContentLines.length; fileContentLinesIndex++)
    {
        if (fileContentLines[fileContentLinesIndex].contains(searchTerm))
        {
            continue;
        }

        fileContents.append(fileContentLines[fileContentLinesIndex] + System.lineSeparator());
    }

    FileUtils.writeStringToFile(targetFile, fileContents.toString().trim());
}

private static void emptyFile(File targetFile) throws FileNotFoundException,
        IOException
{
    RandomAccessFile randomAccessFile = new RandomAccessFile(targetFile, "rw");

    randomAccessFile.setLength(0);
    randomAccessFile.close();
}

나는 Narek이 (저에 따르면) 약간 더 효율적이고 이해하기 쉬운 코드를 만들어야했던 솔루션을 리팩토링했습니다. Java의 최신 기능인 임베디드 자동 리소스 관리를 사용하고 이해하고 사용하기 더 쉬운 Scanner 클래스를 사용했습니다.

편집 된 주석이있는 코드는 다음과 같습니다.

public class RemoveLineInFile {

    private static File file;

    public static void main(String[] args) {
        //create a new File
        file = new File("hello.txt");
        //takes in String that you want to get rid off
        removeLineFromFile("Hello");
    }


    public static void removeLineFromFile(String lineToRemove) {


        //if file does not exist, a file is created

            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    System.out.println("File "+file.getName()+" not created successfully");
                }
            }

            // Construct the new temporary file that will later be renamed to the original
            // filename.
            File tempFile = new File(file.getAbsolutePath() + ".tmp");

           //Two Embedded Automatic Resource Managers used
            // to effectivey handle IO Responses
          try(Scanner scanner = new Scanner(file)) {
              try (PrintWriter pw = new PrintWriter(new FileWriter(tempFile))) {

                  //a declaration of a String Line Which Will Be assigned Later
                  String line;

                  // Read from the original file and write to the new
                  // unless content matches data to be removed.
                  while (scanner.hasNextLine()) {
                      line = scanner.nextLine();
                      if (!line.trim().equals(lineToRemove)) {

                          pw.println(line);
                          pw.flush();
                      }
                  }
                  // Delete the original file
                  if (!file.delete()) {
                      System.out.println("Could not delete file");
                      return;
                  }

                  // Rename the new file to the filename the original file had.
                  if (!tempFile.renameTo(file))
                      System.out.println("Could not rename file");
              }
          }
        catch (IOException e)
        {
            System.out.println("IO Exception Occurred");
        }

    }



}

이 시도:

public static void main(String[] args) throws IOException {

    File file = new File("file.csv");

    CSVReader csvFileReader = new CSVReader(new FileReader(file));

    List<String[]> list = csvFileReader.readAll();

    for (int i = 0; i < list.size(); i++) {
        String[] filter = list.get(i);
        if (filter[0].equalsIgnoreCase("bbb")) {
            list.remove(i);
        }
    }
    csvFileReader.close();
    CSVWriter csvOutput = new CSVWriter(new FileWriter(file));

    csvOutput.writeAll(list);
    csvOutput.flush();

    csvOutput.close();
}

오래된 질문이지만 쉬운 방법은 다음과 같습니다.

  • 파일을 반복하여 새 배열 목록에 각 줄을 추가합니다.
  • 배열을 반복하고 일치하는 문자열을 찾은 다음 remove 메서드를 호출합니다.
  • 배열을 다시 반복하여 각 행을 파일에 인쇄하고 추가에 대한 부울은 기본적으로 파일을 대체하는 false 여야합니다.

이 솔루션은를 사용 RandomAccessFile하여 제거 할 문자열 다음에 나오는 파일 부분 만 캐시합니다. String제거하려는 항목을 찾을 때까지 스캔 합니다. 그런 다음 발견 된 문자열 모든 데이터를 복사 다음 발견 된 문자열 위에 쓰고 그 이후모든 데이터 를 씁니다. 마지막으로 초과 데이터를 제거하기 위해 파일 크기를 자릅니다.

public static long scanForString(String text, File file) throws IOException {
    if (text.isEmpty())
        return file.exists() ? 0 : -1;
    // First of all, get a byte array off of this string:
    byte[] bytes = text.getBytes(/* StandardCharsets.your_charset */);

    // Next, search the file for the byte array.
    try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {

        List<Integer> matches = new LinkedList<>();

        for (long pos = 0; pos < file.length(); pos++) {
            byte bite = dis.readByte();

            for (int i = 0; i < matches.size(); i++) {
                Integer m = matches.get(i);
                if (bytes[m] != bite)
                    matches.remove(i--);
                else if (++m == bytes.length)
                    return pos - m + 1;
                else
                    matches.set(i, m);
            }

            if (bytes[0] == bite)
                matches.add(1);
        }
    }
    return -1;
}

public static void remove(String text, File file) throws IOException {
    try (RandomAccessFile rafile = new RandomAccessFile(file, "rw");) {
        long scanForString = scanForString(text, file);
        if (scanForString == -1) {
            System.out.println("String not found.");
            return;
        }
        long remainderStartPos = scanForString + text.getBytes().length;
        rafile.seek(remainderStartPos);
        int remainderSize = (int) (rafile.length() - rafile.getFilePointer());
        byte[] bytes = new byte[remainderSize];
        rafile.read(bytes);
        rafile.seek(scanForString);

        rafile.write(bytes);
        rafile.setLength(rafile.length() - (text.length()));
    }
}

용법:

파일 내용 : ABCDEFGHIJKLMNOPQRSTUVWXYZ

메서드 호출 : remove("ABC", new File("Drive:/Path/File.extension"));

결과 내용 : DEFGHIJKLMNOPQRSTUVWXYZ

이 솔루션은 cacheSize메모리가 우려되는 경우 특정 지정 가능한으로 제거하도록 쉽게 수정할 수 있습니다 . 여기에는 파일의 나머지 부분을 반복하여 크기의 일부를 계속해서 바꾸는 작업 만 포함됩니다 cacheSize. 그럼에도 불구하고이 솔루션은 일반적으로 전체 파일을 메모리에 캐싱 하거나 임시 디렉토리에 복사 하는 것보다 훨씬 낫습니다 .


이 솔루션은 입력 파일을 한 줄씩 읽고 각 줄을 StringBuilder 변수에 씁니다. 찾고있는 내용과 일치하는 줄을 발견 할 때마다 해당 줄을 작성하지 않습니다. 그런 다음 파일 내용을 삭제하고 StringBuilder 변수 내용을 넣습니다.

public void removeLineFromFile(String lineToRemove, File f) throws FileNotFoundException, IOException{
    //Reading File Content and storing it to a StringBuilder variable ( skips lineToRemove)
    StringBuilder sb = new StringBuilder();
    try (Scanner sc = new Scanner(f)) {
        String currentLine;
        while(sc.hasNext()){
            currentLine = sc.nextLine();
            if(currentLine.equals(lineToRemove)){
                continue; //skips lineToRemove
            }
            sb.append(currentLine).append("\n");
        }
    }
    //Delete File Content
    PrintWriter pw = new PrintWriter(f);
    pw.close();

    BufferedWriter writer = new BufferedWriter(new FileWriter(f, true));
    writer.append(sb.toString());
    writer.close();
}

참고 URL : https://stackoverflow.com/questions/1377279/find-a-line-in-a-file-and-remove-it

반응형