I am trying to delete and rename a file however the delete() and rename() function does not work. I can't seem to find the bug in the code as it should run properly by logic (i think). Can anyone tell me why it can't delete a fill. this code works except deleting old txt and renaming temp.txt to old file.
public Boolean deleteItem(String item){
try{
// creating and opening file
File f = new File("temp.txt");
f.delete(); // to delete existing data inside file;
File old = new File(file);
FileWriter writer = new FileWriter(new File("temp.txt"), true);
FileReader fr = new FileReader(old);
BufferedReader reader = new BufferedReader(fr);
String s;
// creating temporary item object
String[] strArr;
//searching for data inside the file
while ((s = reader.readLine()) != null){
strArr = s.split("\\'");
if (!strArr[0].equals(item)){
writer.append(s + System.getProperty("line.separator"));
}
}
//rename old file to file.txt
old.delete();
boolean successful = f.renameTo(new File(file));
writer.flush();
writer.close();
fr.close();
reader.close();
return successful;
}
catch(Exception e){ e.printStackTrace();}
return false;
}
The logic seems a little tangled. Here's what I think it looks like.
You delete file.txt
You create a new file.txt and copy 'file' into it
You delete 'file'
You rename file.txt to 'file'
You close input and output files
My guess would be that your operating system (unspecified) is preventing deletes and renames of open files. Move the closing to before the delete/rename. And check the return from those functions.
Aside: as a minor improvement to readability, you don't need to keep calling 'new File(xxx)' with the same xxx. A File is just a representation of the name of the file. Do it once. And 'File tempFile = new File("file.txt")' would be easier to follow than calling it 'f'.
Don't use the old java.io.File. It is notorious for its lax error handling and useless error messages. Use the "newer" NIO.2 java.nio.file.Path and the java.nio.file.Files methods that were added in Java 7.
E.g. the file.delete() method returns false if the file was not deleted. No exception is thrown, so you'll never know why, and since you don't even check the return value, you don't know that it didn't delete the file either.
The file isn't deleted because you still have it open. Close the files before attempting to delete+rename, and do it using try-with-resources, also added in Java 7.
Your code should be the following, through capturing exceptions and turning them into a boolean return value is error-prone (see issue with file.delete()).
public boolean deleteItem(String item){
try {
// creating and opening file
Path tempFile = Paths.get("temp.txt");
Files.deleteIfExists(tempFile); // Throws exception if delete failed
Path oldFile = Paths.get(file);
try ( BufferedWriter writer = Files.newBufferedWriter(tempFile);
BufferedReader reader = Files.newBufferedReader(oldFile); ) {
//searching for data inside the file
for (String line; (line = reader.readLine()) != null; ) {
String[] strArr = line.split("\\'");
if (! strArr[0].equals(item)){
writer.append(line + System.lineSeparator());
}
}
} // Files are flushed and closed here
// replace file with temp file
Files.delete(oldFile); // Throws exception if delete failed
Files.move(tempFile, oldFile); // Throws exception if rename failed
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Basically you want to remove selected lines from a text file.
The following code uses the stream API1. It filters out all the unwanted lines and writes the lines that you do want to a temporary file. Then it renames the temporary file to your original file, thus effectively removing the unwanted lines from the original file. Note that I am assuming that your "global" variable file is a string.
/* Following imports required.
import java.io.File
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
*/
Path path = Paths.get(file);
final PrintWriter[] pws = new PrintWriter[1];
try {
File tempFile = File.createTempFile("temp", ".txt");
tempFile.deleteOnExit();
pws[0] = new PrintWriter(tempFile);
Files.lines(path)
.filter(l -> !item.equals(l.split("'")[0]))
.forEach(l -> pws[0].println(l));
pws[0].flush();
pws[0].close();
Files.move(tempFile.toPath(), path, StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
finally {
if (pws[0] != null) {
pws[0].close();
}
}
1 Stream API was introduced in Java 8
Related
I am writing code to process a list of tar.gz files, inside which there are multiple, csv files. I have encountered the error below
com.opencsv.exceptions.CsvMalformedLineException: Unterminated quoted field at end of CSV line. Beginning of lost text: [,,,,,,
]
at com.opencsv.CSVReader.primeNextRecord(CSVReader.java:245)
at com.opencsv.CSVReader.flexibleRead(CSVReader.java:598)
at com.opencsv.CSVReader.readNext(CSVReader.java:204)
at uk.ac.shef.inf.analysis.Test.readAllLines(Test.java:64)
at uk.ac.shef.inf.analysis.Test.main(Test.java:42)
And the code causing this problem is below, on line B.
public class Test {
public static void main(String[] args) {
try {
Path source = Paths.get("/home/xxxx/Work/data/amazon/labelled/small/Books_5.json.1.tar.gz");
InputStream fi = Files.newInputStream(source);
BufferedInputStream bi = new BufferedInputStream(fi);
GzipCompressorInputStream gzi = new GzipCompressorInputStream(bi);
TarArchiveInputStream ti = new TarArchiveInputStream(gzi);
CSVParser parser = new CSVParserBuilder().withStrictQuotes(true)
.withQuoteChar('"').withSeparator(',').
.withEscapeChar('|'). // Line A
build();
BufferedReader br = null;
ArchiveEntry entry;
entry = ti.getNextEntry();
while (entry != null) {
br = new BufferedReader(new InputStreamReader(ti)); // Read directly from tarInput
System.out.format("\n%s\t\t > %s", new Date(), entry.getName());
try{
CSVReader reader = new CSVReaderBuilder(br).withCSVParser(parser)
.build();
List<String[]> r = readAllLines(reader);
} catch (Exception ioe){
ioe.printStackTrace();
}
System.out.println(entry.getName());
entry=ti.getNextEntry(); // Line B
}
}catch (Exception e){
e.printStackTrace();
}
}
private static List<String[]> readAllLines(CSVReader reader) {
List<String[]> out = new ArrayList<>();
int line=0;
try{
String[] lineInArray = reader.readNext();
while(lineInArray!=null) {
//System.out.println(Arrays.asList(lineInArray));
out.add(lineInArray);
line++;
lineInArray=reader.readNext();
}
}catch (Exception e){
System.out.println(line);
e.printStackTrace();
}
System.out.println(out.size());
return out;
}
}
I also attach a screenshot of the actual line within the csv file that caused this problem here, look at line 5213. I also include a test tar.gz file here: https://drive.google.com/file/d/1qHfWiJItnE19-BFdbQ3s3Gek__VkoUqk/view?usp=sharing
While debugging, I have some questions.
I think the issue is the \ character in the data file (line 5213 above), which is the escape character in Java. I verified this idea by adding line A to my code above, and it works. However, obviously I don't want to hardcode this as there can be other characters in the data causing same issue. So my question 1 is: is there anyway to tell Java to ignore escape characters? Something like the opposite of withEscapeChar('|')? UPDATE: the answer is to use '\0', thanks to the first comment below.
When debugging, I notice that my program stops working on the next .csv file within the tar.gz file as soon as it hit the above exception. To explain what I mean, inside the tar.gz file included in the above link, there are two csvs: _10.csv and _110.csv. The problematic line is in _10.csv. When my program hit that line, an exception is thrown and the program moves on to the next file _110.csv (entry=ti.getNextEntry();). This file is actually fine, but the method readAllLines that is supposed to read this next csv file will throw the same exception immediately on the first line. I don't think my code is correct, especially the while loop: I suspect the input stream was still stuck at the previous position that caused the exception. But I don't know how to fix this. Help please?
using RFC4180Parser worked for me.
I'm trying to write multiple ArrayLists to a text file. However, it keeps overwriting to the existing content. I want to keep the existing content of the text file and keep adding ArrayLists to it.
Here is my code:
public static void writeText(String outputFile, String[] array) {
Path file = Paths.get(outputFile);
try (BufferedWriter writer = Files.newBufferedWriter(file)) {
for (String aVal : array)
writer.write(aVal + "\r\n"); // Note addition of line terminator
} catch (IOException err) {
System.err.println(err.getMessage());
}
} // end writeText
I think using path is the problem because it empties the existing file.
Any suggestions on how to fix this
Use the append option
try (BufferedWriter writer = Files.newBufferedWriter(file,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND)) {
DO this in your code:
try (BufferedWriter writer = Files.newBufferedWriter(logFile,
StandardOpenOption.CREATE, StandardOpenOption.APPEND))
StandardOpenOption.APPEND ensures files is open in append mode
I want to merge huge files containing strings into one file and tried to use nio2. I do not want to load the whole file into memory, so I tried it with BufferedReader:
public void mergeFiles(filesToBeMerged) throws IOException{
Path mergedFile = Paths.get("mergedFile");
Files.createFile(mergedFile);
List<Path> _filesToBeMerged = filesToBeMerged;
try (BufferedWriter writer = Files.newBufferedWriter(mergedFile,StandardOpenOption.APPEND)) {
for (Path file : _filesToBeMerged) {
// this does not work as write()-method does not accept a BufferedReader
writer.append(Files.newBufferedReader(file));
}
} catch (IOException e) {
System.err.println(e);
}
}
I tried it with this, this works, hower, the format of the strings (e.g. new lines, etc is not copied to the merged file):
...
try (BufferedWriter writer = Files.newBufferedWriter(mergedFile,StandardOpenOption.APPEND)) {
for (Path file : _filesToBeMerged) {
// writer.write(Files.newBufferedReader(file));
String line = null;
BufferedReader reader = Files.newBufferedReader(file);
while ((line = reader.readLine()) != null) {
writer.append(line);
writer.append(System.lineSeparator());
}
reader.close();
}
} catch (IOException e) {
System.err.println(e);
}
...
How can I merge huge Files with NIO2 without loading the whole file into memory?
If you want to merge two or more files efficiently you should ask yourself, why on earth are you using char based Reader and Writer to perform that task.
By using these classes you are performing a conversion of the file’s bytes to characters from the system’s default encoding to unicode and back from unicode to the system’s default encoding. This means the program has to perform two data conversion on the entire files.
And, by the way, BufferedReader and BufferedWriter are by no means NIO2 artifacts. These classes exists since the very first version of Java.
When you are using byte-wise copying via real NIO functions, the files can be transferred without being touched by the Java application, in the best case the transfer will be performed directly in the file system’s buffer:
import static java.nio.file.StandardOpenOption.*;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MergeFiles
{
public static void main(String[] arg) throws IOException {
if(arg.length<2) {
System.err.println("Syntax: infiles... outfile");
System.exit(1);
}
Path outFile=Paths.get(arg[arg.length-1]);
System.out.println("TO "+outFile);
try(FileChannel out=FileChannel.open(outFile, CREATE, WRITE)) {
for(int ix=0, n=arg.length-1; ix<n; ix++) {
Path inFile=Paths.get(arg[ix]);
System.out.println(inFile+"...");
try(FileChannel in=FileChannel.open(inFile, READ)) {
for(long p=0, l=in.size(); p<l; )
p+=in.transferTo(p, l-p, out);
}
}
}
System.out.println("DONE.");
}
}
With
Files.newBufferedReader(file).readLine()
you create a new Buffer everytime and it gets always reset in the first line.
Replace with
BufferedReader reader = Files.newBufferedReader(file);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
and .close() the reader when done.
readLine() does not yield the line ending ("\n" or "\r\n"). That was the error.
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.write("\r\n"); // Windows
}
You might also disregard this filtering of (possibly different) line endings, and use
try (OutputStream out = new FileOutputStream(file);
for (Path source : filesToBeMerged) {
Files.copy(path, out);
out.write("\r\n".getBytes(StandardCharsets.US_ASCII));
}
}
This writes a newline explicitly, in the case that the last line does not end with a line break.
There might still be a problem with the optional, ugly Unicode BOM character to mark the text as UTF-8/UTF-16LE/UTF-16BE at the beginning of the file.
I am using Scanner to read the File contents. For that I am using the following code.
public static void main (String[] args) throws IOException {
File file = new File("/File.txt");
Scanner sc = new Scanner(file);
while(sc.hasNextLine()) {
// Until the end
System.out.print(sc.nextLine());
}
sc.close();
}
But this code always throws FileNotFoundException. I have tried Googling this, but I can't find where to check the file. Secondly, I have created files with same name in almost every directory to check when would the Code catch the presence of file.
You can see in the Package I have created a file named File.txt so that code can find it whereever it looks for.
In the Java docs, I get to know that the File accepts a String parameter as
File file = new File("file_name");
But what sort or what would be the param here, isn't told. Can I get the help?
I think you want File file = new File("File.txt"); instead of File file = new File("/File.txt");, get rid of the slash. If what you want is a relative path, you want .\File.txt
As #deterministicFail says in the comments, it is not a good idea to hardcode path separators, instead use System.getProperty("path.separator"); This way your code should work in multiple plataforms, so your code would be:
To make it plataform independent (Asuming you are using a relative path):
File file = new File("." + System.getProperty("path.separator") + "File.txt");
Replace the line
File file = new File("/File.txt");
with
File file = new File(".\\File.txt");
or
File file = new File("File.txt");
File f=new File("testFile.txt");
For this kind of referral you need to put file in root of your eclipse project (In parallel of src). This problem is only when you are Using Eclipse IDE.
Best solution for this kind of problems is checking AbsolutePath of the file
System.out.println(f.getAbsolutePath());
It will give you path where your code is looking for file.
There are two possibilities if you are looking for the file in the working directory then either use "File.txt" or "./File.txt". In case of windows one more option would be to use ".\File.txt).
If that is not what you are looking for, you can check which path the file refers to using either of the two sysouts immediately after instantiating the file, which will give you the absolute path on your machine.
File f = new File("/File.txt");
System.out.println(f.getAbsolutePath());
System.out.println(f.getAbsoluteFile().getAbsolutePath());
I have never done it the way you did but this is how I read files.
This is the purpose of the class FileInpuStream. I use a buffer to get bytes.
If it is only a problem of path, why don't you simply use the complete path ? You can copy paste it from the file information.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// object I use to read files
fis = new FileInputStream(new File("File.txt"));
byte[] buf = new byte[8];
int n = 0;
// while there is something in the file
while ((n = fis.read(buf)) >= 0) {
for (byte bit : buf) {
// do what you want
System.out.print("\t" + bit + "(" + (char) bit + ")");
System.out.println("");
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Try not to use the / in File.txt, and if you really have to, use the backslash instead \ since you're in Windows
My purpose is to rename one file. What I'm doing is: I'm searching a particular string in a text file. Among So many files and if that particular text is found then I want rename that text file with a given string.
Here is what I have tried:
String opcode="OPCODES"; // String that I want to search.
File file = new File("D:\\CFF1156"); // All files are inside this folder.
System.out.println("The File Name is :"+file.getName());
File[] f = file.listFiles();
System.out.println("The Length of File is :"+f.length);
Boolean flag=false;
StringBuffer contents = new StringBuffer();
BufferedReader reader = null;
for(int i=0;i<f.length;i++)
{
try{
reader = new BufferedReader(new FileReader(f[i]));
String text = null;
while ((text = reader.readLine()) != null)
{
if(text.contains(opcode))
{
System.out.println("Found");
System.out.println("The File Containing the Search text is :"+f[i]);
f[i].renameTo(new File("D://CFF1156/changed.txt"));
System.out.println("renamed :"+(f[i].renameTo(new File("D://CFF1156/changed.txt"))));
if(f[i].renameTo(new File("D://CFF1156/changed.txt")))
{
System.out.println("Successfully renamed");
}
else
{
System.out.println("Error");
}
}
}
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
finally
{
try
{
if (reader != null)
{
reader.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
The above code is searching the particular file. But I'm not able to rename it.
What would be a working Solution to this problem?
You are renaming with the same name, in a loop. Fix that thing first. Furthermore, take the returned boolean value in a variable by renameTo() method, and use that variable in your if.
I am having a hard time reading the code as given, but there is a renameTo method on File (see this javadoc). Note that it takes a File object representing the desired pathname, and returns a boolean.
From Javadoc of renameTo
..., it might not be atomic, and it
might not succeed if a file with the
destination abstract pathname already
exists.
You check the returned boolean in the second renameTo command. Remove all renameTo commands, or store the boolean of the first command and print this boolean to the console.
First thing, you sometimes use the \ and other times //, im on Mac, so not sure what you should use on Windows.
Second, you are renaming all the files to the same name.
Fix:
boolean renamed = f[i].renameTo(new File("D://CFF1156/changed"+ i + ".txt"));
System.out.println(renamed?"Succesfully renamed":"Error");