I'm trying to output some data to file in Java and do not understand why when I run this code...
try {
File file = new File("demo.txt");
BufferedWriter out = new BufferedWriter(new FileWriter(file));
int i = 127;
int j = 128;
System.out.println(Integer.toHexString(i));
System.out.println(Integer.toHexString(j));
out.write(i);
out.write(j);
out.close();
} catch (IOException e) {}
...the following is output to the console log:
7f
80
but when I open the file demo.txt with a hex editor I see the bytes 7f and 3f. Why does out.write() output most int values correctly (example 127) but alters others (example 128)? How can I write the data to the file straight?
FileWriter should be used to write character streams. If you are trying to write binary data, then a FileOutputStream is appropriate. If you replace your FileWriter with a FileOutputStream and your BufferedWriter with a BufferedOutputStream you will find that the data is written as you'd expect.
FileWriter is character and encoding-aware which means that it may transform data that you pass through it to match a character encoding. But to be honest I don't know exactly what transformation is going on here.
Related
There are so many Input/Output Classes in Java.
It is really a mess. You do not know which to use.
Which functions does operating system offer ? There will be one
to read one byte of a file or many bytes of a file I guess.
So for example if I use this.
String path = "C:\\Users\\myName\\test.txt";
FileOutputStream fos = new FileOutputStream(path);
fos.write(333);
If I open it with a text editor it shows me letter "G" . Already I do not understand this.
And this code does not write anything, the file is empty weirdly.
String path = "C:\\Users\\myName\\test.txt";
FileOutputStream fos = new FileOutputStream(path);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos));
out.write("something");
All these I/O classes just confuse me. What does buffered mean. It reads 1000 Bytes at once. So
there is operating function to straight away read 1000 Bytes of a file I guess.
You need to close the instances of BufferedWriter out and FileOutputStream fos, after invoking the out.write("something"), then only the file gets created successfully with the contents you are trying to write.
public static void main(String[] args) throws IOException {
String path = "C:\\Users\\myName\\test.txt";
FileOutputStream fos = new FileOutputStream(path);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos));
out.write("something");
out.close(); // Closes the stream, flushing it first.
fos.close(); // Closes this file output stream and releases any system resources associated with this stream.
}
Closing the instances of BufferedWriter and FileOutputStream will solve the issue.
fos.write(333) => The number has been written to the file and when you open the file it opens in ASCII format. You can use below code.
public static void main(String[] args) throws IOException {
FileWriter fw=new FileWriter("D:\\test.txt");
fw.write("Hello! This is a sample text");
System.out.println("Writing successful");
fw.close();
/* your code
String path = "D:\\test1.txt";
FileOutputStream fos = new FileOutputStream(path);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fos));
out.write("Hello! This is a sample text");
out.close();
fos.close();
*/
}
There are so many Input/Output Classes in Java. It is really a mess. You do not know which to use.
The Files class is by far the easiest to use. For instance,
Files.writeString(Paths.get("test.txt"), "hello world!");
creates a text file named "test.txt" containing the text "hello world!".
The other classes are only needed if you want to do something fancy (for instance, deal with files too big to fit in main memory). For instance, suppose you wanted to read a huge log file (hundreds of gigabytes long) and wanted to write each line containing a particular word to another file. If you were to open the file with
Files.readAllLines(Paths.get("huge.log"));
you'd receive an OutOfMemoryError because the file doesn't fit in main memory. To work around that, we must read the file piece-wise, and that is what all those Reader and Writer classes (or InputStream and OutputStream, if you're dealing with binary files) are good for:
try (
var reader = Files.newBufferedReader(Paths.get("huge.log"));
var writer = Files.newBufferedWriter(Paths.get("interesting.log"));
) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(searchWord)) {
writer.write(line);
writer.write('\n');
}
}
}
As you can see, their use is quite a bit more complicated. For one, we must close the Reader and Writer once we are done with them, which is easiest accomplished with the try with resources statement shown above.
Closing is necessary because most operating systems limit the number of files that can be open at once. Closing also gives any Buffered* classes the opportunity to empty their buffers, ensuring that any data still in buffers is passed on to the file system.
If we fail to close, as you did in your example code, the file remains open until our program exits, upon which time any data in the buffers is lost, resulting in the incomplete file you found.
I am trying to write data to a binary file and am having difficulty. When I run this method I don't get any output to the file. Also when it comes to writing my "Date" object, I can't seem to find a write method that takes it as a parameter. The object consists of an int month, day, and year. How can I write it into a binary file properly?
Also, does "File" work for binary as well? I have only previously used it for regular .txt files and I'm not sure if it can be used the same way in this situation. Thanks!
Here is my write method:
private void writeBinary(){
//String fileName = getUserInput();
String fileTest = "BinaryMonster.bin";
File file = new File(fileTest);
DataOutputStream out;
try{
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file, true)));
if(!(file.exists())){
file.createNewFile();
System.out.println("New file created...");
}
for(int i = 0; i < monsterAttacks.size(); i++){
out.writeInt(monsterAttacks.get(i).getID());
out.write(monsterAttacks.get(i).getDate()); //getting error
out.writeUTF(monsterAttacks.get(i).getName() + monsterAttacks.get(i).getLocation() + monsterAttacks.get(i).getReporter());
}
} catch(IOException e) {
e.printStackTrace();
}
}
It is giving error because you are writing whole object of date into the file using DataOutputStream, which don't allow you to do that.
Write it in the form of String into the file. It will be better.
out.writeUTF(monsterAttacks.get(i).getDate().toString());
But if you want to save the whole object into the file, then you need to use ObjectOutputStream which write whole serialized objects into the file.
And it is better approach to flush and close the file.
out.flush();
out.close();
I'm trying to extract a file from my jar and copying it into the temp directory.
To read the file within the jar, I am using a DataInputStream, to write the file in the temp directory, I am using a DataOutputStream.
The file I am trying to extract has a file size of 310 kilobytes, my copied file only contains 114 bytes after I've called my method (this is also the number of bytes my method prints to the console).
Here is my method:
private static void extractFile(String pathInJar, String fileToCopy) {
File outputFile = new File(System.getProperty("java.io.tmpdir") + "/LDEngine/"+fileToCopy);
boolean couldDirsBeCreated = outputFile.getParentFile().mkdirs();
if(couldDirsBeCreated && !outputFile.exists()) {
int x;
int actualBytesRead = 0;
byte[] tmpByteArray = new byte[4096];
try(
DataOutputStream output = new DataOutputStream(new FileOutputStream(outputFile));
DataInputStream in = new DataInputStream(LibLoader.class.getResourceAsStream("/libs/natives/"+pathInJar))
){
while((x=in.read(tmpByteArray)) != -1) {
output.write(tmpByteArray);
actualBytesRead += x;
}
} catch(Exception e) {
System.err.println("Fatal error: Could not write file!");
System.exit(1);
}
System.out.println(actualBytesRead);
}
}
The file I am trying to copy is a .dll, so it's binary data I'm dealing with.
The question is why is this happening and what am I doing wrong?
This does not explain why your method stops so soon, but you need to take care of it or you will have an even stranger problem with the result data being completely garbled.
From the APi doc of DataInputStream.read():
Reads some number of bytes from the contained input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer.
You need to use that return value and call the write() method that takes and offset and length.
I wrote a data to text file, but data in file are incorrect. I think it is problem with OutpubStream, because I display data on previous steps, and they were correct.
private void Output(File file2) {
// TODO Auto-generated method stub
OutputStream os;
try {
os = new FileOutputStream(file2); //file2-it is my output file, all normal with him
Iterator<Integer> e=mass.iterator();
int r=0;
while(e.hasNext()){
r=e.next();
System.out.println(r);//display data-all be correct
os.write(r);//I think problem create in this step/
}
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Input data file1.txt
10
56
2
33
45
21
15
68
54
85
Output data file2.txt
3 strahge tokens plus !-68DU
thanks for answers, excuse me for my english.
The line
os.write(r);
Writes the binary value of integer r to the file.
Use something like:
os.write(String.valueOf(r));
and you probably want new lines:
os.write(String.valueOf(r)+"\n");
FileOutputStream is used to write binary raw Data. As specified in document :
FileOutputStream is meant for writing streams of raw bytes such as
image data. For writing streams of characters, consider using
FileWrite
Since you are writing integers to the file so what you need is text-output Stream like PrintWriter. It can be used in your code as follows:
PrintWriter pw = new PrintWriter(file2); //file2-it is my output file, all normal with it
Iterator<Integer> e=mass.iterator();
int r=0;
while(e.hasNext()){
r=e.next();
pw.print(r);
pw.println();//for new line
}
pw.close();
use FileWriter instead of FileOutputStream as your data is text and you probably want to use a stream of characters
you could consider transforming the string into a bytecode:
System.out.println(r);// display data-all be correct
String line = (String.valueOf(r) + "\n");
os.write(line.getBytes());
I'm trying to familiarize myself with the different types of stream IOs Java has to offer, so I wrote this little piece of code here.
public static void main(String[] args) throws IOException {
String str = "English is being IOed!\nLine 2 has a number.\n中文字體(Chinese)";
FileOutputStream fos = new FileOutputStream("ByteIO.txt");
Scanner fis = new Scanner(new FileInputStream("ByteIO.txt"));
FileWriter fw = new FileWriter("CharIO.txt");
Scanner fr = new Scanner(new FileReader("CharIO.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("BufferedByteIO.txt"));
Scanner bis = new Scanner(new BufferedInputStream(new FileInputStream("BufferedByteIO.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter("BufferedCharIO.txt"));
Scanner br = new Scanner(new BufferedReader(new FileReader("BufferedCharIO.txt")));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream((new FileOutputStream("DataBufferedByteIO.txt"))));
Scanner dis = new Scanner(new DataInputStream(new BufferedInputStream((new FileInputStream("DataBufferedByteIO.txt")))));
try {
System.out.printf("ByteIO:\n");
fos.write(str.getBytes());
while (fis.hasNext())
System.out.print(fis.next());// in the form of a String
System.out.printf("\nCharIO:\n");
fw.write(str);
while (fr.hasNext())
System.out.print(fr.next());
System.out.printf("\nBufferedByteIO:\n");
bos.write(str.getBytes());
bos.flush();// buffer is not full, so you'll need to flush it
while (bis.hasNext())
System.out.print(bis.next());
System.out.printf("\nBufferedCharIO:\n");
bw.write(str);
bw.flush();// buffer is not full, so you'll need to flush it
while (br.hasNext())
System.out.print(br.next());
System.out.printf("\nDataBufferedByteIO:\n");
dos.write(str.getBytes());
//dos.flush();// dos doesn't seem to need this...
while (dis.hasNext())
System.out.print(dis.next());
} finally {
fos.close();
fis.close();
fw.close();
fr.close();
bos.close();
br.close();
dos.close();
dis.close();
}
}
All it does is just write a pre-defined string into the file and then read it. The problem arises when I run the code, I get this:
ByteIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
CharIO:
//<--Empty line here
BufferedByteIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
BufferedCharIO:
EnglishisbeingIOed!Line2hasanumber.中文字體(Chinese)
DataBufferedByteIO:
//<--Empty line here
The files are all populated with the correct data, so I suppose something is wrong with the scanner, but I just don't know what went wrong, and I hope somebody can point the mistake out for me.
The files are all populated with the same data. That's weird, according to Java I/O Streams, Byte Streams can only process single bytes, and only Character Streams can process Unicode, so shouldn't Byte Streams spit out gibberish when processing Chinese characters, which are UTF-16 (I think)? What exactly is the difference between a Byte Stream and a Character Stream (fos vs fw)?
On a partially unrelated topic, I thought Byte Streams were used to work with binary data such as music and images, I also thought that the data Byte Streams spit out should be illegible, but I seem to be wrong, am I? Exactly which I/O Stream Class(es) should I work with if I'm dealing with binary data?
An important concept to understand here is that of encoding.
String/char[]/Writer/Reader are used to deal with textual data of any kind.
byte[]/OutputStream/InputStream are used to deal with binary data. Also, a file on your disk only every stores binary data (yes, that's true, it will hopefully be a bit more clear in a minute).
Whenever you convert between those two worlds some kind of encoding will be in play. In Java, there are several ways to convert between those worlds without specifying an encoding. In this case, the platform default encoding will be used (which one this is depends on your platform and configuration/locale). [*]
The task of an encoding is to convert some given binary data (usually from a byte[]/ByteBuffer/InputStream) to textual data (usually into char[]/CharBuffer/Writer) or the other way around.
How exactly this happens depends on the encoding used. Some encodings (such as the ISO-8859-* family) are a simple mapping from byte values to corresponding unicode codepoints, others (such as UTF-8) are more complex and a single unicode codepoint can be anything from 1 to 4 bytes.
There's a quite nice article that gives a basic overview over the whole encoding issue titled: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
[*] Using the platform default encoding is usually not desired, because it makes your program un-portable and hard to use, but that's beside the point for this post.
Using BufferedInputStream and DataInputStream does not alter the content of the data.
Byte stream is for reading binary data. It is not suitable here.
Character stream is for reading text, the scanner assumes you are reading new line terminated lines. (Which you don't appear to have)
If I run
String str = "English is being IOed!\nLine 2 has a number.\n\u4E2D\u6587\u5b57\u9ad4(Chinese)\n";
Writer fw = new OutputStreamWriter(new FileOutputStream("ReaderWriter.txt"), "UTF-8");
fw.write(str);
fw.close();
Reader fr = new InputStreamReader(new FileInputStream("ReaderWriter.txt"), "UTF-8");
Scanner scanner = new Scanner(fr);
String next = "";
while (scanner.hasNext()) {
next = scanner.next();
System.out.println(next);
}
for (int i = 0; i < next.length(); i++)
System.out.println(Integer.toHexString((int) next.charAt(i)));
fr.close();
I get
English
is
being
IOed!
Line
2
has
a
number.
????(Chinese)
4e2d
6587
5b57
9ad4
28
43
68
69
6e
65
73
65
29
You can see that the original characters are preserved. The '?' means the character could not be displayed on my terminal or my character encoding. (I don't know why)