Je cherche un petit extrait de code qui trouvera une ligne dans le fichier et supprimera cette ligne (pas le contenu mais la ligne) mais ne pourra pas le trouver. Ainsi, par exemple, j'ai dans un fichier suivant:
myFile.txt :
aaa
bbb
ccc
ddd
Besoin d'une fonction comme celle-ci: public void removeLine(String lineContent)
, et si je réussis removeLine("bbb")
, j'obtiens un fichier comme celui-ci:
myFile.txt:
aaa
ccc
ddd
Cette solution peut ne pas être optimale ou jolie, mais cela fonctionne. Il lit dans un fichier d'entrée ligne par ligne, en inscrivant chaque ligne dans un fichier de sortie temporaire. Chaque fois qu'il rencontre une ligne qui correspond à ce que vous recherchez, il ignore de l'écrire. Il renomme ensuite le fichier de sortie. J'ai omis le traitement des erreurs, la fermeture des lecteurs/rédacteurs, etc. de l'exemple. Je suppose également qu’il n’ya pas d’espace au début ou à la fin de la ligne que vous recherchez. Modifiez le code autour de trim () si nécessaire pour pouvoir trouver une correspondance.
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();
}
}
J'ai trouvé cela sur Internet.
Vous voulez faire quelque chose comme ce qui suit:
(Je n'écrirai pas le code réel, car cela ressemble à un devoir, mais n'hésitez pas à poser d'autres questions sur des éléments spécifiques qui vous posent problème)
En utilisant Apache commons-io et Java 8, vous pouvez utiliser
List<String> lines = FileUtils.readLines(file);
List<String> updatedLines = lines.stream().filter(s -> !s.contains(searchString)).collect(Collectors.toList());
FileUtils.writeLines(file, updatedLines, false);
Donc, chaque fois que j'entends quelqu'un dire qu'il veut filtrer le texte, je pense immédiatement à aller à Streams (principalement parce qu'il existe une méthode appelée filter
qui filtre exactement comme vous en avez besoin). Une autre réponse mentionne l'utilisation de Stream
s avec la bibliothèque Apache commons-io, mais j'ai pensé qu'il serait intéressant de montrer comment cela peut être fait en Java 8 standard. Voici le formulaire le plus simple:
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);
}
Je pense qu'il n'y a pas grand chose à expliquer là-dedans, Files.lines
obtient un Stream<String>
des lignes du fichier, filter
supprime les lignes que nous ne voulons pas, puis collect
place toutes les lignes du nouveau fichier dans un List
. Nous écrivons ensuite la liste par-dessus le fichier existant avec Files.write
, en utilisant l'option supplémentaire TRUNCATE
afin de remplacer l'ancien contenu du fichier.
Bien sûr, cette approche présente l’inconvénient de charger chaque ligne en mémoire car elles sont toutes stockées dans une variable List
avant d’être réécrites. Si nous voulions simplement modifier sans stocker, nous aurions besoin d'utiliser une forme de OutputStream
pour écrire chaque nouvelle ligne dans un fichier lors de son passage dans le flux, comme ceci:
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);
}
Peu de choses ont changé dans cet exemple. Fondamentalement, au lieu d’utiliser collect
pour rassembler le contenu du fichier en mémoire, nous utilisons forEach
de sorte que chaque ligne passant par filter
soit envoyée à la PrintWriter
pour être écrite immédiatement dans le fichier et non stockée. Nous devons l'enregistrer dans un fichier temporaire, car nous ne pouvons pas écraser le fichier existant en même temps que nous le lisons encore. À la fin, nous renommons le fichier temporaire pour remplacer le fichier existant.
Voici. Cette solution utilise une variable DataInputStream
pour rechercher la position de la chaîne à remplacer et utilise une variable FileChannel
pour remplacer le texte à cette position exacte. Il ne remplace que la première occurrence de la chaîne trouvée. Cette solution ne stocke pas une copie du fichier entier quelque part , (soit le fichier RAM, soit un fichier temporaire), elle ne fait que modifier la partie du fichier trouvée.
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 */)));
}
}
Entrée: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Appel de méthode:
replaceText("QRS", "000", new File("path/to/file");
Fichier résultant: 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();
}
Voici la classe complète. Dans le fichier ci-dessous, "emplacement" fait référence au chemin d'accès réel du fichier.
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!");
}
}
}
J'ai refactoré la solution que Narek devait créer (selon moi) un code légèrement plus efficace et facile à comprendre. J'ai utilisé la gestion automatique des ressources intégrée, une fonctionnalité récente de Java, ainsi qu'une classe Scanner, plus facile à comprendre et à utiliser.
Voici le code avec les commentaires édités:
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");
}
}
}
Vieille question, mais un moyen facile est de:
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");
}
}
Cette solution utilise RandomAccessFile
pour ne mettre en cache que la partie du fichier postérieure à la chaîne à supprimer. Il analyse jusqu'à trouver le String
à supprimer. Ensuite, il copie toutes les données after la chaîne trouvée, puis les écrit sur la chaîne trouvée, et tout ce qui suit. Enfin, il tronque la taille du fichier pour supprimer les données en excès.
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()));
}
}
Contenu du fichier: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Appel de méthode: remove("ABC", new File("Drive:/Path/File.extension"));
Contenu résultant: DEFGHIJKLMNOPQRSTUVWXYZ
Cette solution pourrait facilement être modifiée pour être supprimée avec un certain cacheSize
spécifiable, si la mémoire pose un problème. Cela impliquerait simplement d'itérer sur le reste du fichier pour remplacer continuellement des portions de taille, cacheSize
. Quoi qu’il en soit, cette solution est généralement bien meilleure que la mise en cache d’un fichier entier en mémoire, ou sa copie dans un répertoire temporaire, etc.
Essaye ça:
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();
}
Cette solution lit dans un fichier d'entrée ligne par ligne, en écrivant chaque ligne dans une variable StringBuilder. Chaque fois qu'il rencontre une ligne qui correspond à ce que vous recherchez, il ignore de l'écrire. Ensuite, il supprime le contenu du fichier et place le contenu variable de 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();
}
Cette solution nécessite que la bibliothèque Apache Commons IO soit ajoutée au chemin de génération. Cela fonctionne en lisant tout le fichier et en écrivant chaque ligne, mais seulement si le terme recherché n'est pas contenu.
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();
}