Getting NULL value at the end while writing to the file - java

I have problem while writing to the file. I want to write contents of my input file to output file but while writing to the file, I am getting NULL value written at the end of file.
What's the reason behind that?
My code is:
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class FileReading {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
FileInputStream fi=new
FileInputStream("E:\\Tejas\\NewData_FromNov\\New_Folder\\bb.txt");
DataInputStream di=new DataInputStream(fi);
BufferedReader buf=new BufferedReader(new InputStreamReader(di));
FileOutputStream fout=new FileOutputStream("E:\\Tejas\\NewData_FromNov\\New_Folder\\Out_bb.txt");
int ss;
byte[] input=new byte[500];
int len=input.length;
while((ss=di.read(input,0,len))!=-1)
{
System.out.println(ss);
//fout.write(ss);
fout.write(input,0,len);
}
fout.close();
}
}

You're always writing out the full buffer, even if you've only read part of it because the third argument to write is len (the length of the buffer) instead of ss (the number of bytes read). Your loop should look like this:
int bytesRead; // Easier to understand than "ss"
byte[] buffer = new byte[500];
while((bytesRead = di.read(buffer, 0, buffer.length)) != -1)
{
System.out.println(bytesRead);
fout.write(buffer, 0, bytesRead);
}
Additionally:
You should close both the input and output streams in finally blocks to ensure they're always closed (even if there's an exception).
You don't need a DataInputStream - just a FileInputStream is fine here.
You're not using your BufferedReader at all.
Consider using Guava or a similar third-party library which contains utility methods to do all of this.

The read method returns the number of actually read bytes, or -1 if the end of the stream has been reached. So you should only write ss bytes, and not len bytes:
while ((ss = di.read(input, 0, len)) != -1) {
System.out.println(ss);
fout.write(input, 0, ss);
}
Note thet the DataInputStream and the BufferedReader are completely unnecessary here.

Related

Is there an -1 at the end of an Inputstream?

I am quite new to programming.
While reading the article Byte Streams in "Basic I/O" in The Java Tutorials by Oracle, I came accross this code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBytes {
public static void main(String[] args) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("xanadu.txt");
out = new FileOutputStream("outagain.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
I do not understand the condition of the while-loop. Is -1 some kind of sign that the Message is over? Does the FileOutputStream add it at the end?
Thank you all for your attention. I hope you have a wonderfull sylvester.
To add to the other answers, the tool for figuring this out is the documentation.
For the 'read' method of FileInputStream:
public int read()
throws IOException
Reads a byte of data from this input stream. This method blocks if no input is yet available. Specified by:
read in class InputStream
Returns: the next byte of data, or -1 if the
end of the file is reached.
This is definitive.
All standard Java classes are documented in this manner. In case of uncertainty, a quick check will reassure you.
EDIT: "Signals that an end of file or end of stream has been reached unexpectedly during input.
This exception is mainly used by data input streams, which generally expect a binary file in a specific format, and for which an end of stream is an unusual condition. Most other input streams return a special value on end of stream."
The right way is to catch EOFException to find out is it end of file or not, but in tihs case reading chars as EOF -1 is returned and not null, and it's working because there is no char for negative ascii, it's the same to check while ((c = in.read()) >= 0) {}, so you can use != -1 and it will work.

What's the fastest way to read from InputStream?

I'm trying to read from an input stream of a HttpURLConnection:
InputStream input = conn.getInputStream();
InputStreamReader isr = new InputStreamReader((input));
BufferedReader br = new BufferedReader(isr);
StringBuilder out = new StringBuilder("");
String output;
while ((output = br.readLine()) != null) {
out.append(output);
}
This does take too much time when the input stream contains a lot of data. Is it possible to optimize this?
Maybe this will be a bit faster, cause the new Stream API in Java 8 ist using internaly a parallel mechanism:
package testing;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.stream.Stream;
public class StreamTest {
/**
* #param args the command line arguments
* #throws java.io.IOException
*/
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.google.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Stream<String> s = br.lines();
s.parallel().forEach(System.out::println);
}
}
}
There's nothing slow about this code. You can read millions of lines a second with this, if the input arrives fast enough. Your time probably isn't spent reading the input stream at all, but in either blocking waiting for input or in appending to the StringBuilder.
But you shouldn't be doing this at all. Most files can be processed a line at a time or a record at a time. Compilers process them a token at a time, and there aren't many more complex file-processing tasks than compilation. It's possible.
In java inputstream we have method read(byte b[],off,len)
which reads the from the input stream into the given byte array.
Here off is the starting index of the array, len is the maximum number of byte to be read and b[] is the byte array.
Read method will attempt to read maximum of len number of bytes but this method returns number of actual byte read as many times i will fail to read the desired number of bytes.
Here is the example:-
FileInputStream i=new FileInputStream("file path");
FIleOutputStream o=new FileOutputStream("file path");
byte a[]=new byte[1024];
for(int j;(j=i.read(a,0,1024))!=-1;){
o.write(a,0,j);
}

In java is there a readObject() alternative for RandomAccessFile

I'm trying to save a couple of Strings but I'm currently using ObjectInputStream, which apparently doesn't save my data in a permanent manner. Here is the code which I commented in my project. It saves the string in a temporal manner. Anytime I exit my program, puff the data is gone:
ObjectInputStream FileIn= new ObjectInputStream(new FileInputStream("cars.txt"));
//AND HERE IS THE CODE FOR THE RandomAccessFile VERSION:
RandomAccessFile FileIn = new RandomAccessFile("cars.txt", "rw");
au=(Cars)FileIn.readObject(); //THIS readObject(), is giving me errors
//Cars is a Class
Is there any other alternative that I can use to read RandomAccessFile... Please help and thanks.
Just like FileInputStream, you need to wrap a RandomAccessFile in an ObjectInputStream. i.e. RandomAccessFile doesn't buy you anything.
final RandomAccessFile raf = new RandomAccessFile("file.dat", "r");
ObjectInputStream ois = new ObjectInputStream(new InputStream() {
#Override
public int read(byte[] b, int off, int len) throws IOException {
return raf.read(b, off, len);
}
#Override
public int read() throws IOException {
return raf.read();
}
});
For simple String objects is far easier using plain DataInputStream / DataOutputStream:
package test;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
public class TestFile {
static final String FILE = "/tmp/cars.txt";
public static void main(String[] args) {
try {
List<String> strs = new ArrayList<String>();
strs.add("Audi");
strs.add("Seat");
strs.add("Renault");
saveStrings(strs);
strs = loadStrings();
System.out.println("Read strings: " + strs);
} catch (Exception e) {
}
}
static List<String> loadStrings() throws Exception {
DataInputStream dis = null;
List<String> list = new ArrayList<String>();
try {
dis = new DataInputStream(new FileInputStream(FILE));
while (dis.available() > 0) {
list.add(dis.readUTF());
}
} finally {
if (dis != null)
dis.close();
}
return list;
}
static void saveStrings(List<String> list) throws Exception {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream(FILE));
for (String str : list) {
dos.writeUTF(str);
}
} finally {
if (dos != null)
dos.close();
}
}
}
If you are asking whether you can use RandomAccessFile to seek around inside an object stream and read objects then the short answer is "no". Serialized object streams are heavily encoded with backwards pointers to previously used objects including previously dumped class definitions, etc..
Serialization stream specification with some format details.
Here's some more details on the serialization format.
Discussion about random writing from Java docs.
We had a similar requirement and wrote some code which closes and re-opens the serialized stream once and a while and recorded the positions of these break points. This didn't give us the ability to read a particular object but it did give us the ability to append to serialized stream and to skip over a particular portion of the file -- skip to the next break.
Well you have to invoke, writeObject() instead of readObject() which is actually to read from disk to memory, and of course when the program ends, so does the memory used by that program.

How to read parts of binary file again if DataInputStream does not support mark/reset

I need to read a section of a structured binary file by passing an index. However, DataInputStream does not support mark/reset. How can I achieve what I want? Are there any other classes that allow me to easily achieve this?
import java.io.*;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
class Test {
public static int getInt(DataInputStream stream, int index) throws IOException {
int offset = index * 4; // size of int
stream.reset();
stream.skip(offset);
return stream.readInt();
}
public static void main(String[] args) {
String filename = "test.data";
try {
DataOutputStream ostream = new DataOutputStream(new FileOutputStream(filename));
for (int i=0; i<10; i++) {
ostream.writeInt(i);
}
ostream.close();
DataInputStream istream = new DataInputStream(new FileInputStream(filename));
istream.mark(0);
int i0 = getInt(istream, 0);
int i3 = getInt(istream, 3);
int i5 = getInt(istream, 5);
System.out.printf("i0 = %d, i3 = %d, i5 = %d\n", i0, i3, i5);
istream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
It is not DataInputStream that doesn't support mark/reset. DataInputStream simply delegates the calls to mark/reset to the underlying stream (in this case a FileInputStream). The FileInputStream does however not support mark/reset operations (iirc). The solution to this problem is to first wrap the FileInputStream in a BufferedInputStream before passing it to the DataInputStream. That should make it possible to use the desired operations. Ie:
DataInputStream istream = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
Also, I am not entirely sure, but from what I understand you might be using the argument for mark incorrectly. According to the JavaDoc the argument means:
the maximum limit of bytes that can be read before the mark position becomes invalid.
Thus, calling mark with the argument zero would not be particularly useful.
wrap in a BufferedInputStream it implements mark
btw your mark call should give the amount of bytes that you expect to be read until a reset will happen. if you read past that the mark becomes invalid and reset will throw
or use a RandomAccessFile

Read a file line by line in reverse order

I have a java ee application where I use a servlet to print a log file created with log4j. When reading log files you are usually looking for the last log line and therefore the servlet would be much more useful if it printed the log file in reverse order. My actual code is:
response.setContentType("text");
PrintWriter out = response.getWriter();
try {
FileReader logReader = new FileReader("logfile.log");
try {
BufferedReader buffer = new BufferedReader(logReader);
for (String line = buffer.readLine(); line != null; line = buffer.readLine()) {
out.println(line);
}
} finally {
logReader.close();
}
} finally {
out.close();
}
The implementations I've found in the internet involve using a StringBuffer and loading all the file before printing, isn't there a code light way of seeking to the end of the file and reading the content till the start of the file?
[EDIT]
By request, I am prepending this answer with the sentiment of a later comment: If you need this behavior frequently, a "more appropriate" solution is probably to move your logs from text files to database tables with DBAppender (part of log4j 2). Then you could simply query for latest entries.
[/EDIT]
I would probably approach this slightly differently than the answers listed.
(1) Create a subclass of Writer that writes the encoded bytes of each character in reverse order:
public class ReverseOutputStreamWriter extends Writer {
private OutputStream out;
private Charset encoding;
public ReverseOutputStreamWriter(OutputStream out, Charset encoding) {
this.out = out;
this.encoding = encoding;
}
public void write(int ch) throws IOException {
byte[] buffer = this.encoding.encode(String.valueOf(ch)).array();
// write the bytes in reverse order to this.out
}
// other overloaded methods
}
(2) Create a subclass of log4j WriterAppender whose createWriter method would be overridden to create an instance of ReverseOutputStreamWriter.
(3) Create a subclass of log4j Layout whose format method returns the log string in reverse character order:
public class ReversePatternLayout extends PatternLayout {
// constructors
public String format(LoggingEvent event) {
return new StringBuilder(super.format(event)).reverse().toString();
}
}
(4) Modify my logging configuration file to send log messages to both the "normal" log file and a "reverse" log file. The "reverse" log file would contain the same log messages as the "normal" log file, but each message would be written backwards. (Note that the encoding of the "reverse" log file would not necessarily conform to UTF-8, or even any character encoding.)
(5) Create a subclass of InputStream that wraps an instance of RandomAccessFile in order to read the bytes of a file in reverse order:
public class ReverseFileInputStream extends InputStream {
private RandomAccessFile in;
private byte[] buffer;
// The index of the next byte to read.
private int bufferIndex;
public ReverseFileInputStream(File file) {
this.in = new RandomAccessFile(File, "r");
this.buffer = new byte[4096];
this.bufferIndex = this.buffer.length;
this.in.seek(file.length());
}
public void populateBuffer() throws IOException {
// record the old position
// seek to a new, previous position
// read from the new position to the old position into the buffer
// reverse the buffer
}
public int read() throws IOException {
if (this.bufferIndex == this.buffer.length) {
populateBuffer();
if (this.bufferIndex == this.buffer.length) {
return -1;
}
}
return this.buffer[this.bufferIndex++];
}
// other overridden methods
}
Now if I want to read the entries of the "normal" log file in reverse order, I just need to create an instance of ReverseFileInputStream, giving it the "revere" log file.
This is a old question. I also wanted to do the same thing and after some searching found there is a class in apache commons-io to achieve this:
org.apache.commons.io.input.ReversedLinesFileReader
I think a good choice for this would be using RandomFileAccess class. There is some sample code for back-reading using this class on this page. Reading bytes this way is easy, however reading strings might be a bit more challenging.
If you are in a hurry and want the simplest solution without worrying too much about performance, I would give a try to use an external process to do the dirty job (given that you are running your app in a Un*x server, as any decent person would do XD)
new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("tail yourlogfile.txt -n 50 | rev").getProcess().getInputStream()))
A simpler alternative, because you say that you're creating a servlet to do this, is to use a LinkedList to hold the last N lines (where N might be a servlet parameter). When the list size exceeds N, you call removeFirst().
From a user experience perspective, this is probably the best solution. As you note, the most recent lines are the most important. Not being overwhelmed with information is also very important.
Good question. I'm not aware of any common implementations of this. It's not trivial to do properly either, so be careful what you choose. It should deal with character set encoding and detection of different line break methods. Here's the implementation I have so far that works with ASCII and UTF-8 encoded files, including a test case for UTF-8. It does not work with UTF-16LE or UTF-16BE encoded files.
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
public class ReverseLineReader {
private static final int BUFFER_SIZE = 8192;
private final FileChannel channel;
private final String encoding;
private long filePos;
private ByteBuffer buf;
private int bufPos;
private byte lastLineBreak = '\n';
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
public ReverseLineReader(File file, String encoding) throws IOException {
RandomAccessFile raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
filePos = raf.length();
this.encoding = encoding;
}
public String readLine() throws IOException {
while (true) {
if (bufPos < 0) {
if (filePos == 0) {
if (baos == null) {
return null;
}
String line = bufToString();
baos = null;
return line;
}
long start = Math.max(filePos - BUFFER_SIZE, 0);
long end = filePos;
long len = end - start;
buf = channel.map(FileChannel.MapMode.READ_ONLY, start, len);
bufPos = (int) len;
filePos = start;
}
while (bufPos-- > 0) {
byte c = buf.get(bufPos);
if (c == '\r' || c == '\n') {
if (c != lastLineBreak) {
lastLineBreak = c;
continue;
}
lastLineBreak = c;
return bufToString();
}
baos.write(c);
}
}
}
private String bufToString() throws UnsupportedEncodingException {
if (baos.size() == 0) {
return "";
}
byte[] bytes = baos.toByteArray();
for (int i = 0; i < bytes.length / 2; i++) {
byte t = bytes[i];
bytes[i] = bytes[bytes.length - i - 1];
bytes[bytes.length - i - 1] = t;
}
baos.reset();
return new String(bytes, encoding);
}
public static void main(String[] args) throws IOException {
File file = new File("my.log");
ReverseLineReader reader = new ReverseLineReader(file, "UTF-8");
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
public static class ReverseLineReaderTest extends TestCase {
public void test() throws IOException {
File file = new File("utf8test.log");
String encoding = "UTF-8";
FileInputStream fileIn = new FileInputStream(file);
Reader fileReader = new InputStreamReader(fileIn, encoding);
BufferedReader bufReader = new BufferedReader(fileReader);
List<String> lines = new ArrayList<String>();
String line;
while ((line = bufReader.readLine()) != null) {
lines.add(line);
}
Collections.reverse(lines);
ReverseLineReader reader = new ReverseLineReader(file, encoding);
int pos = 0;
while ((line = reader.readLine()) != null) {
assertEquals(lines.get(pos++), line);
}
assertEquals(lines.size(), pos);
}
}
}
you can use RandomAccessFile implements this function,such as:
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import com.google.common.io.LineProcessor;
public class FileUtils {
/**
* 反向读取文本文件(UTF8),文本文件分行是通过\r\n
*
* #param <T>
* #param file
* #param step 反向寻找的步长
* #param lineprocessor
* #throws IOException
*/
public static <T> T backWardsRead(File file, int step,
LineProcessor<T> lineprocessor) throws IOException {
RandomAccessFile rf = new RandomAccessFile(file, "r");
long fileLen = rf.length();
long pos = fileLen - step;
// 寻找倒序的第一行:\r
while (true) {
if (pos < 0) {
// 处理第一行
rf.seek(0);
lineprocessor.processLine(rf.readLine());
return lineprocessor.getResult();
}
rf.seek(pos);
char c = (char) rf.readByte();
while (c != '\r') {
c = (char) rf.readByte();
}
rf.readByte();//read '\n'
pos = rf.getFilePointer();
if (!lineprocessor.processLine(rf.readLine())) {
return lineprocessor.getResult();
}
pos -= step;
}
}
use:
FileUtils.backWardsRead(new File("H:/usersfavs.csv"), 40,
new LineProcessor<Void>() {
//TODO implements method
.......
});
The simplest solution is to read through the file in forward order, using an ArrayList<Long> to hold the byte offset of each log record. You'll need to use something like Jakarta Commons CountingInputStream to retrieve the position of each record, and will need to carefully organize your buffers to ensure that it returns the proper values:
FileInputStream fis = // .. logfile
BufferedInputStream bis = new BufferedInputStream(fis);
CountingInputStream cis = new CountingInputSteam(bis);
InputStreamReader isr = new InputStreamReader(cis, "UTF-8");
And you probably won't be able to use a BufferedReader, because it will attempt to read-ahead and throw off the count (but reading a character at a time won't be a performance problem, because you're buffering lower in the stack).
To write the file, you iterate the list backwards and use a RandomAccessFile. There is a bit of a trick: to properly decode the bytes (assuming a multi-byte encoding), you will need to read the bytes corresponding to an entry, and then apply a decoding to it. The list, however, will give you the start and end position of the bytes.
One big benefit to this approach, versus simply printing the lines in reverse order, is that you won't damage multi-line log messages (such as exceptions).
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Inside of C:\\temp\\vaquar.txt we have following content
* vaquar khan is working into Citi He is good good programmer programmer trust me
* #author vaquar.khan#gmail.com
*
*/
public class ReadFileAndDisplayResultsinReverse {
public static void main(String[] args) {
try {
// read data from file
Object[] wordList = ReadFile();
System.out.println("File data=" + wordList);
//
Set<String> uniquWordList = null;
for (Object text : wordList) {
System.out.println((String) text);
List<String> tokens = Arrays.asList(text.toString().split("\\s+"));
System.out.println("tokens" + tokens);
uniquWordList = new HashSet<String>(tokens);
// If multiple line then code into same loop
}
System.out.println("uniquWordList" + uniquWordList);
Comparator<String> wordComp= new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
if(o1==null && o2 ==null) return 0;
if(o1==null ) return o2.length()-0;
if(o2 ==null) return o1.length()-0;
//
return o2.length()-o1.length();
}
};
List<String> fs=new ArrayList<String>(uniquWordList);
Collections.sort(fs,wordComp);
System.out.println("uniquWordList" + fs);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static Object[] ReadFile() throws IOException {
List<String> list = Files.readAllLines(new File("C:\\temp\\vaquar.txt").toPath(), Charset.defaultCharset());
return list.toArray();
}
}
Output:
[Vaquar khan is working into Citi He is good good programmer programmer trust me
tokens[vaquar, khan, is, working, into, Citi, He, is, good, good, programmer, programmer, trust, me]
uniquWordList[trust, vaquar, programmer, is, good, into, khan, me, working, Citi, He]
uniquWordList[programmer, working, vaquar, trust, good, into, khan, Citi, is, me, He]
If you want to Sort A to Z then write one more comparater
Concise solution using Java 7 Autoclosables and Java 8 Streams :
try (Stream<String> logStream = Files.lines(Paths.get("C:\\logfile.log"))) {
logStream
.sorted(Comparator.reverseOrder())
.limit(10) // last 10 lines
.forEach(System.out::println);
}
Big drawback: only works when lines are strictly in natural order, like log files prefixed with timestamps but without exceptions

Categories