Recently I am doing a code review, the code is like this:
File j = new File(aFile);
System.out.println(j.length());
BufferedReader fileReader = new BufferedReader(new FileReader(j));
BufferedWriter fileWriter = new BufferedWriter(new FileWriter(aFile.getPath());
System.out.println(j.length());
I have two questions:
Is j a duplicate of aFile, because I have seen other huge methods for copying files, like here.
The first System.out.println() prints 32 and the second, after creating a file reader, prints 0. So, why are the contents getting deleted? Could someone explain what's happening here?
I put those System.out.println() statements to check if the file is empty or not.
Solution:
After Reading through the answers, I think I found what's wrong with the code. If j is just a reference, then the fileWriter is trying to write into the same file and it is cyclic. Am I right here?
EDIT: This is not a duplicate of suggested question, as the whole confusion was thinking that the j is clone or duplicate of aFile.
You're not showing us everything, are you?
The presented code definitely does not change or delete the file, as is already indicated by the names of the classes you are using: BufferedReader, FileReader (note Reader in both).
I thought there might be a slim chance that some operating systems would lock the file once you create the Readers, hence not even allowing a File object to read the length() property anymore. However, I couldn't find that documented or reported anywhere, so I highly doubt it.
I ran the following code, where test is a plain text file containing 0123456789 (length 10):
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class StackOverflow {
public static void main(String[] args) {
File f = new File("test");
System.out.println("Length before: " + f.length());
try {
BufferedReader fileReader = new BufferedReader(new FileReader(f));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("Length after: " + f.length());
}
}
Result:
Length before: 10
Length after: 10
Hence, I suspect the issue lies elsewhere.
EDIT:
Now that OP updated the question, we finally have the relevant line:
BufferedWriter fileWriter = new BufferedWriter(new FileWriter(aFile.getPath());
That's why the file is empty and its length 0. FileWriter will open the file for writing and overwrite the existing contents, if any. You can prevent this by passing in a second parameter, making use of another constructor of FileWriter, one that accepts an append flag:
public FileWriter(String fileName, boolean append) throws IOException
public FileWriter(File file, boolean append) throws IOException
Constructs a FileWriter object given a File object/name. If the second argument is true, then bytes will be written to the end of the file rather than the beginning.
In other words, if you don't want the contents to be overridden, change your above line to:
BufferedWriter fileWriter = new BufferedWriter(new FileWriter(aFile.getPath(), true);
1) j is not a duplicate, it is a reference to a new file object that wraps the actual file.
2) There is no way this code should delete (or even change) the file. Is there any more code?
1) Is j a duplicate of aFile, because I have seen other huge methods for copying files, like here and here.
It is a File object constructed from aFile, whatever that may be. This process has nothing whatsoever to do with copying files, whether huge or hugely or otherwise. File just wraps a file name. Not its contents. Your first link has nothing to do with copying files either.
2) The first result prints 32 and the second result after creating a file reader prints 0. So, why are the contents getting deleted?
Obviously this is not the real code. The real test is whether fileReader.read() immediately returns -1.
Related
I'm reading a file line by line, and I am trying to make it so that if I get to a line that fits my specific parameters (in my case if it begins with a certain word), that I can overwrite that line.
My current code:
try {
FileInputStream fis = new FileInputStream(myFile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.startsWith("word")) {
// replace line code here
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
...where myFile is a File object.
As always, any help, examples, or suggestions are much appreciated.
Thanks!
RandomAccessFile seems a good fit. Its javadoc says:
Instances of this class support both reading and writing to a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer; input operations read bytes starting at the file pointer and advance the file pointer past the bytes read. If the random access file is created in read/write mode, then output operations are also available; output operations write bytes starting at the file pointer and advance the file pointer past the bytes written. Output operations that write past the current end of the implied array cause the array to be extended. The file pointer can be read by the getFilePointer method and set by the seek method.
That said, since text files are a sequential file format, you can not replace a line with a line of a different length without moving all subsequent characters around, so to replace lines will in general amount to reading and writing the entire file. This may be easier to accomplish if you write to a separate file, and rename the output file once you are done. This is also more robust in case if something goes wrong, as one can simply retry with the contents of the initial file. The only advantage of RandomAccessFile is that you do not need the disk space for the temporary output file, and may get slight better performance out of the disk due to better access locality.
Your best bet here is likely going to be reading in the file into memory (Something like a StringBuilder) and writing what you want your output file to look like into the StringBuilder. After you're done reading in the file completely, you'll then want to write the contents of the StringBuilder to the file.
If the file is too large to accomplish this in memory you can always read in the contents of the file line by line and write them to a temporary file instead of a StringBuilder. After that is done you can delete the old file and move the temporary one in its place.
An old question, recently worked on this. Sharing the experience
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public static void updateFile(Path file) {
// Get all the lines
try (Stream<String> stream = Files.lines(file,StandardCharsets.UTF_8)) {
// Do the replace operation
List<String> list = stream.map(line -> line.replaceAll("test", "new")).collect(Collectors.toList());
// Write the content back
Files.write(file, list, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}
I'm trying to write a program that will find the specific words in txt file, and write the whole line in separate file. For now my program just rewrites the whole file and saves it into the new one. This part is needed for the rest of the program where these lines will be replaced, but that I already created. I'm just a beginner in Java and I can't handle it. Will I need to use regex?
import java.io.*;
public class change {
public static void main(String[] args) {
try {
BufferedWriter bw = new BufferedWriter(
new FileWriter("path\\file.txt"));
BufferedReader br = new BufferedReader(
new FileReader("path\\newfile.txt"));
String s;
while((s = br.readLine()) != null){
bw.write(s + "\n");
}
br.close();
bw.close();
} catch(Exception ex){
return;
}
}
}
Multiple issues with this code.
Deplorable exception handling
This code, if a problem occurs, will take all useful information about your exception (which is at least 4 things: The exception's type, the exception's message, the stack trace, and the causual chain), and tosses it in the garbage.
You will write bugs. Loads of em. Your assumptions about where your app run will change on you.
Exceptions are crucial in managing this.
Stop writing code like this. The fix is easy, and even reduces and simplifies your code! Simply pile throws Exception at the end of your main declaration (public static void main(String[] args) throws Exception {) and remove the try, the catch, and the return in the catch.
This way, the exception bubbles up to whatever invokes main itself, and that will 'handle' it by printing all the various useful parts and exiting your app. Which is what you want.
charset violations
Files are bags of bytes, but Writer and Reader work in terms of characters. Anytime bytes are converted to characters or vice versa, an encoding is applied. UTF-8 is an encoding. So is ISO-8859-1, MacRoman, CP452, etcetera.
If you don't see the encoding being applied then usually that means 'platform default' is applied and you almost never want that. It leads to code that seems to work fine until you run it elsewhere or on different files and then all hell breaks loose.
The fix is to either use APIs which have baked into their specification that they default to UTF_8 (such as the new Files API), or to explicitly specify. In passing, unfortunately, FileWriter and FileReader are not fit for purpose; do not ever use these classes, they are effectively broken as designed. Their API is also obsolete, there's a newer API.
Using the old APIs, you'd fix it as follows:
new BufferedWriter(new InputStreamWriter(new FileInputStream("path\\file.txt"), StandardCharsets.UTF_8));
Using the new APIs, well, that's a bit more involved, see below.
Resource management violation
When you open resources, you must explicitly close them too. Java is a garbage collected language, but the 'point' of garbage collection is that the JVM will run collection when it deems neccessary, and it might be days before it does. Thus, any object that takes up more than simply memory if you leave it laying about needs explicit closing. "Handles" to files is one such resource: Your OS has a limited supply of these and will flat out refuse to let a process open more files once it has opened a certain amount. Your code opens files but may not close them anymore: If an exception occurs, that br.close() and bw.close() line will never be executed.
Java has a tool for this: Automatic Resource Management (ARM), also called 'try-with-resources'. Replace this:
BufferedWriter bw = ....;
// do stuff with the writer
bw.close();
with:
try (BufferedWriter bw = ....) {
// do stuff with the writer
}
The {} mark where you use the writer: Java ensures that no matter how you 'exit' out of these {}, the resource WILL be closed. Whether you just get to the end of this block, or you return/break/continue out of it, or an exception leads you out of it, the resource is closed.
Searching for strings
regexps is one way, but if you're looking for a specific exact string that's overkill. Strings have a .contains() method.
New API
There's a new API. The old File API has a nasty tendency to just return false when things can't be done instead of telling you about it like 'normal' java APIs. It's also got more flexibility: It can handle such things as managing file ownership, file creation stamps, access control, and links. It also has the nice property that the default charset encoding, if you don't specify anything, is UTF-8 instead of the dreaded and extremely useless 'platform default'.
Backslashes
Not neccessary, even on windows. path/file.txt works just as well. It reads easier and is far more common.
var
You can use var instead of writing out the type a second time which can come in handy. var x = new Foo(); is the same as Foo x = new Foo().
Putting it all together
public class Change {
public static void main(String[] args) throws Exception {
try (
var bw = Files.newBufferedWriter(Paths.get("path/newfile.txt"));
var br = Files.newBufferedReader(Paths.get("path/file.txt"));
) {
String s;
while ((s = br.readLine()) != null) {
if (s.contains("StringToFind")) {
// or: s.matches("^.*String[a-zA-Z]WithRegexpToFind.*$")
bw.write(s + "\n");
}
}
}
}
}
I made some code that will find the location of a certain string in a .txt file, which I think is what your looking for.
import java.io.*;
import java.util.*;
public class Help {
public static void main(String[] args) throws Exception {
Scanner input = new Scanner(System.in);
// To edit the string your searching for you can get rid input and edit the text variable
String text = input.nextLine();
String line;
BufferedReader br = new BufferedReader(new FileReader("testFile.txt"));
while((line = br.readLine()) != null){
if(line.indexOf(text) != -1){
// enter what you want to do if the string is found here I just put a println statement which you can get rid of
System.out.println("Found");
}else{
// enter what you want to do if the string is not found here I just put a println statement which you can get rid of
System.out.println("Not Found");
}
}
br.close();
}
}
Links: How to locate text in string, How to read and write files in java
I have a little doubt about following code:
try {
File file = new File("writing");
file.createNewFile();
System.out.println(file.delete());
System.out.println(file.exists());
PrintWriter pw = new PrintWriter(file);
pw.print(324.2342);
pw.flush();
pw.close();
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
System.out.println(br.readLine());
br.close();
} catch(IOException ioE) {
System.out.println("Indeed");
}
Why in this circumstance the method file.delete() apparently says that it works as it returns "true" when executed and it gets also confirmed by the file.exists() method which returns "false". However at runtime I do not get any exception like "IOException the file "writing" does not exist" or something likewise.
Why does the file keep staying in the heap even though deleted physically? Shouldn't it be automatically garbage collected as soon as the delete method gets called? I know it does not because I saw the output.
This is because the File represents a abstract path, see the JavaDoc for it http://docs.oracle.com/javase/6/docs/api/java/io/File.html. It does not represent a file handle in the OS.
The line in your code:
PrintWriter pw = new PrintWriter(file);
Simply creates a new file. Try deleting the file after calling this...
File object represents a path to a physical file on the file system either exists or not. That's why you have exists() (to check if it exists) and createNewFile() (to create the file if it is not found).
Also note that PrintWriter(File file) creates a new file if it does not exist.
Parameters:
file - The file to use as the destination of this writer. If the file
exists then it will be truncated to zero size; otherwise, a new file
will be created. The output will be written to the file and is
buffered.
The File is handle to real file (that exists or not). You create and then delete the file above, as you say - all good so far.
When you come to the PrintWriter later on it creates the file once more when you use it - it doesnt matter that you deleted it before.
In fact depending on your use case this might be exaclty wht you want - you may want to delete an old log file for example before re-createing and writing to it once more.
Finally, nothing in your code will be eligible for garbage collection until your method exist, and even then the underyling file will continue to exist (if you dont delete it agin) - and any garbage colleciton in this case wouldnt effect the underlying file. It'll be deleted after the delete invokation and exist again once youre PrintWriter is done with it.
Hope this helps!
The file doesn't have a link to a particular file, rather to any file pointer by the file's path. With this line you're creating a new file:
PrintWriter pw = new PrintWriter(file);
I'm reading a file line by line, and I am trying to make it so that if I get to a line that fits my specific parameters (in my case if it begins with a certain word), that I can overwrite that line.
My current code:
try {
FileInputStream fis = new FileInputStream(myFile);
DataInputStream in = new DataInputStream(fis);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
if (line.startsWith("word")) {
// replace line code here
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
...where myFile is a File object.
As always, any help, examples, or suggestions are much appreciated.
Thanks!
RandomAccessFile seems a good fit. Its javadoc says:
Instances of this class support both reading and writing to a random access file. A random access file behaves like a large array of bytes stored in the file system. There is a kind of cursor, or index into the implied array, called the file pointer; input operations read bytes starting at the file pointer and advance the file pointer past the bytes read. If the random access file is created in read/write mode, then output operations are also available; output operations write bytes starting at the file pointer and advance the file pointer past the bytes written. Output operations that write past the current end of the implied array cause the array to be extended. The file pointer can be read by the getFilePointer method and set by the seek method.
That said, since text files are a sequential file format, you can not replace a line with a line of a different length without moving all subsequent characters around, so to replace lines will in general amount to reading and writing the entire file. This may be easier to accomplish if you write to a separate file, and rename the output file once you are done. This is also more robust in case if something goes wrong, as one can simply retry with the contents of the initial file. The only advantage of RandomAccessFile is that you do not need the disk space for the temporary output file, and may get slight better performance out of the disk due to better access locality.
Your best bet here is likely going to be reading in the file into memory (Something like a StringBuilder) and writing what you want your output file to look like into the StringBuilder. After you're done reading in the file completely, you'll then want to write the contents of the StringBuilder to the file.
If the file is too large to accomplish this in memory you can always read in the contents of the file line by line and write them to a temporary file instead of a StringBuilder. After that is done you can delete the old file and move the temporary one in its place.
An old question, recently worked on this. Sharing the experience
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public static void updateFile(Path file) {
// Get all the lines
try (Stream<String> stream = Files.lines(file,StandardCharsets.UTF_8)) {
// Do the replace operation
List<String> list = stream.map(line -> line.replaceAll("test", "new")).collect(Collectors.toList());
// Write the content back
Files.write(file, list, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
}
I have to edit the contents of a file and write the edited conted to another file.Here is the code iam using .
import java.io.*;
import java.util.*;
public class TestRef {
ArrayList<String> lines = new ArrayList<String>();
String line= null;
public void printThis(){
try{
FileReader fr = new FileReader("C:\\Users\\questions.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter fw = new FileWriter("C:\\Users\\questions_out.txt");
BufferedWriter out = new BufferedWriter(fw);
while((line=br.readLine()) != null) {
if(line.contains("Javascript"))
line.replace("Javascript"," JAVA");
lines.add(line);
out.write(line);
}
}
catch(Exception e){}
}
public static void main(String [] args){
TestRef tr = new TestRef();
tr.printThis();
}
}
So this is like reading one line at a time and printing it back to the file. But when I execute this code the output file is blank.? Can you please provide me with a sample code, how to read from a file, make change in the content and write the whole file to a new file ?
Well, a few problems:
You're never closing either your input or your output. Closing will also flush - it's possible that something's just not being flushed. You should close stream-based resources in a finally block, so that they end up being closed even in the face of an exception. (Given that you should be closing, I wouldn't bother explicitly flushing as well. Just make sure you close the top-level abstraction - i.e. out (and br).
You're catching Exception and then swallowing it. It could well be that an exception is being thrown, but you're not able to tell because you've swallowed it. You should at least be logging it, and probably stopping at that point. (I'd also suggest catching IOException instead of Exception.)
You're using FileWriter and FileReader which doesn't allow you to specify the input/output encoding - not the issue here, but personally I like to take more control over the encodings I use. I'd suggest using FileInputStream and FileOutputStream wrapped in InputStreamReader and OutputStreamWriter.
You're calling String.replace() and ignoring the result. Strings are immutable - calling replace won't change the existing string. You want:
line = line.replace("Javascript"," JAVA");
You're never using your lines variable, and your line variable would be better as a local variable. It's only relevant within the method itself, so only declare it in the method.
Your code would be easier to follow if it were more appropriately indented. If you're using an IDE, it should be able to do this for you - it makes a huge difference in readability.
The first one is the most likely cause of your current problem, but the rest should help when you're past that. (The point about "replace" will probably be your next issue...)
You are missing out.flush().
BufferedWriters don't write anything until either you flush them, or their buffer fills up.
Close the print writer, outside the loop.
out.flush();
out.close();
Moreover you are writing strings to new lines, if you just want to replace javascript with Java, then you might also wanna write '\n', next line character to new file where old file contains new line.