I'm getting inputstream from MimeMessage. In the InputStream, at the end I want to add \r\n.\r\n
To represent the end of the message.
Please suggest.
You can append it on the fly with
public class ConcatInputStream extends InputStream {
private final InputStream[] is;
private int last = 0;
ConcatInputStream(InputStream[] is) {
this.is = is;
}
public static InputStream of(InputStream... is) {
return new ConcatInputStream(is);
}
#Override
public int read(byte[] b, int off, int len) throws IOException {
for (; last < is.length; last++) {
int read = is[last].read(b, off, len);
if (read >= 0)
return read;
}
throw new EOFException();
}
#Override
public int read() throws IOException {
for (; last < is.length; last++) {
int read = is[last].read();
if (read >= 0)
return read;
}
throw new EOFException();
}
#Override
public int available() throws IOException {
long available = 0;
for(int i = last; i < is.length; i++)
available += is[i].available();
return (int) Math.min(Integer.MAX_VALUE, available);
}
}
In your case you can do
InputStream in =
InputStream in2 = ConcatInputStream.of(in,
new ByteArrayInputStream("\r\n.\r\n".getBytes()));
Just store the InputStraem value in a String, then add it to that String:
BufferedReader input;
if(stream != null){
input = new BufferedReader(new InputStreamReader(
stream));
String responseLine = "";
String server_response = "";
try {
while (((responseLine = input.readLine()) != null) {
server_response = server_response + responseLine + "\r\n";
}
} catch (IOException e) {
}
server_response = server_response + "\r\n.\r\n";
}
am I miss something? or that what you asked for?
Related
https://github.com/essiembre/eclipse-rbe/issues/83
eclipse-rbe
In Eclipse exist file: messagesBundle_ru_RU.properties
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
#Generated by ResourceBundle Editor (http://eclipse-rbe.sourceforge.net)
#Created by JInto - www.guh-software.de
#Sun Nov 18 17:19:12 EET 2012
ABS = \u0410\u0411\u0421
About = \u041E \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0435
Add = \u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0437\u0430\u043F\u0438\u0441\u0438
Add_Condition = \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0443\u0441\u043B\u043E\u0432\u0438\u0435
Additional = \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E
How I can convert this to READABLE text in UTF-8 format?
This is a properties file, and when it was saved to an OutputStream, any character outside of the ISO-8859-1 character set was replaced with a Unicode escape. The Properties.load(InputStream) method will decode this for you. You can then save the properties to a new file, specifying UTF-8 encoding.
static void transcodeProperties(Path src, Path dst) throws IOException {
Properties properties = new Properties();
try (InputStream fis = Files.newInputStream(src);
BufferedInputStream is = new BufferedInputStream(fis)) {
properties.load(is);
}
try (Writer w = Files.newBufferedWriter(dst, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW)) {
properties.store(w, null);
}
}
I created a method of doing what you asked. Keep in mind, I used methods from Apache. I extracted the required methods that way you will not be forced to use that library if you do not want to.
public static void translateFileUnicode(File input, File output) {
LinkedList<String> result = new LinkedList<>();
try {
BufferedReader reader = new BufferedReader(new FileReader(input));
String temp = reader.readLine();
while (temp != null) {
result.add(translate(temp));
temp = reader.readLine();
}
reader.close();
BufferedWriter writer = new BufferedWriter(new FileWriter(output));
for (String str : result) {
writer.write(str + '\n');
}
writer.flush();
writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String translate(final CharSequence input) {
if (input == null) {
return null;
}
try {
final StringWriter writer = new StringWriter(input.length() * 2);
translate(input, writer);
return writer.toString();
} catch (final IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
public static void translate(final CharSequence input, final Writer writer) throws IOException {
Objects.requireNonNull(writer, "writer");
if (input == null) {
return;
}
int pos = 0;
final int len = input.length();
while (pos < len) {
final int consumed = translateUnicode(input, pos, writer);
if (consumed == 0) {
final char c1 = input.charAt(pos);
writer.write(c1);
pos++;
if (Character.isHighSurrogate(c1) && pos < len) {
final char c2 = input.charAt(pos);
if (Character.isLowSurrogate(c2)) {
writer.write(c2);
pos++;
}
}
continue;
}
for (int pt = 0; pt < consumed; pt++) {
pos += Character.charCount(Character.codePointAt(input, pos));
}
}
}
public static int translateUnicode(final CharSequence input, final int index, final Writer out) throws IOException {
if (input.charAt(index) == '\\' && index + 1 < input.length() && input.charAt(index + 1) == 'u') {
int i = 2;
while (index + i < input.length() && input.charAt(index + i) == 'u') {
i++;
}
if (index + i < input.length() && input.charAt(index + i) == '+') {
i++;
}
if (index + i + 4 <= input.length()) {
final CharSequence unicode = input.subSequence(index + i, index + i + 4);
try {
final int value = Integer.parseInt(unicode.toString(), 16);
out.write((char) value);
} catch (final NumberFormatException nfe) {
throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
}
return i + 4;
}
throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '" + input.subSequence(index, input.length())
+ "' due to end of CharSequence");
}
return 0;
}
If you wish to translate the unicode characters from one file into another all at once you can use the translateFileUnicode(File, File) method. If you wish to translate a single String you can use the translate(CharSequence) method. I hope this is what you were looking for.
I have been trying to write a simple code where i can go through a list of filenames, go through each file name, and calculate how many lines are there in each file.
However the code below doesn't seem to work at all (keeps initiating the debug perspective in eclipse).
public class fileScanner {
public static void main(String[] args) throws IOException {
ArrayList<String> list = new ArrayList<String>();
//add files
list.add("C:\\Users\\HuiHui\\Documents\\eclipse\\test.txt");
for (String l : list){
fileScan(l);
}
}
public static int fileScan(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean endsWithoutNewLine = false;
while ((readChars = is.read(c)) != -1) {
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n')
++count;
}
endsWithoutNewLine = (c[readChars - 1] != '\n');
}
if(endsWithoutNewLine) {
++count;
}
return count;
} finally {
is.close();
}
}
}
Can anyone shed some light on this?
Is there a reason why you're using InputStream and created a BufferedInputStream instead of using BufferedReader which does the job for you ?
try this for your filescan method
int filescan(String filename) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(filename));
int count=0;
String s;
while((s=br.nextLine()) != null)
count++;
br.close();
return count;
}
Try LineNumberReader:
public static int fileScan(String filename) throws IOException {
File file = new File(filename);
LineNumberReader lnr = null;
try {
lnr = new LineNumberReader(new FileReader(file));
lnr.skip(file.length());//go to end of file
return lnr.getLineNumber();
} finally {
if(null != lnr) {
lnr.close();
}
}
}
You could use a Scanner to iterate through each file, and then increment an integer for every line that there is.
Example:
while(scanner.hasNextLine()) {
scanner.nextLine();
integer++;
}
Below is a solution from Number of lines in a file in Java
to quickly count the number of lines in a text file.
However, I am trying to write a method that will perform the same task without throwing an 'IOException'.
Under the original solution is my attempt to do this with a nested try-catch block <-- (Is this usually done/frowned upon/ or easily avoidable??) which returns 0 no matter how many lines are in the given file (obviously a fail).
Just to be clear, I am not looking for advice on how to better use the original method that does contain the exception and, therefore, the context within which I am using it is irrelevant to this question.
Can somebody please help me write a method that counts the number of lines in a text file and does not throw any exceptions? (In other words, deals with potential errors with a try-catch.)
Original line counter by martinus:
public static int countLines(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
My Attempt:
public int countLines(String fileName ) {
InputStream input = null;
try{
try{
input = new BufferedInputStream(new FileInputStream(fileName));
byte[] count = new byte[1024];
int lines = 0;
int forChar;
boolean empty = true;
while((forChar = input.read(count)) != -1){
empty = false;
for(int x = 0; x < forChar; x++){
if(count[x] == '\n'){
lines++;
}
}
}
return (!empty && lines == 0) ? 1 : lines + 1;
}
finally{
if(input != null)
input.close();
}
}
catch(IOException f){
int lines = 0;
return lines;
}
}
It is more robust to use char instead of byte for '\n' and return -1 in case of any errors, for example if the filename does not exist:
public static int countLines(String filename) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
char[] c = new char[1024];
int count = 0;
int readChars = 0;
boolean emptyLine = true;
while ((readChars = br.read(c)) != -1) {
for (int i = 0; i < readChars; ++i) {
emptyLine = false;
if (c[i] == '\n') {
++count;
emptyLine = true;
}
}
}
return count + (!emptyLine ? 1 : 0);
} catch (IOException ex) {
return -1;
} finally {
if (br != null)
try {
br.close();
} catch (IOException e) {
// Ignore intentionally
}
}
}
Sharing my attempt.
public static int countLines(String filename) {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
int numLines = 0;
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
numLines = (count == 0 && !empty) ? 1 : count;
} catch (IOException ex) {
numLines = 0;
} catch (FileNotFoundException ex) {
System.out.println("File not found.");
numLines = 0;
} finally {
is.close();
}
return numLines;
}
I trying to write a code to stream from shoutcast server
and I use the below code and give me javax.sound.sampled.UnsupportedAudioFileException
how I can solve the exception
public static void streamSampledAudio(URL url)
throws IOException, UnsupportedAudioFileException,
LineUnavailableException
{
AudioInputStream ain = null; // We read audio data from here
SourceDataLine line = null; // And write it here.
try {
InputStream is = url.openStream();
BufferedInputStream bis = new BufferedInputStream( is );
ain=AudioSystem.getAudioInputStream(bis);
AudioFormat format = ain.getFormat( );
DataLine.Info info=new DataLine.Info(SourceDataLine.class,format);
if (!AudioSystem.isLineSupported(info)) {
AudioFormat pcm =
new AudioFormat(format.getSampleRate( ), 16,
format.getChannels( ), true, false);
ain = AudioSystem.getAudioInputStream(pcm, ain);
format = ain.getFormat( );
info = new DataLine.Info(SourceDataLine.class, format);
}
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format);
int framesize = format.getFrameSize( );
byte[ ] buffer = new byte[4 * 1024 * framesize]; // the buffer
int numbytes = 0; // how many bytes
boolean started = false;
for(;;) { // We'll exit the loop when we reach the end of stream
int bytesread=ain.read(buffer,numbytes,buffer.length-numbytes);
if (bytesread == -1) break;
numbytes += bytesread;
if (!started) {
line.start( );
started = true;
}
int bytestowrite = (numbytes/framesize)*framesize;
line.write(buffer, 0, bytestowrite);
int remaining = numbytes - bytestowrite;
if (remaining > 0)
System.arraycopy(buffer,bytestowrite,buffer,0,remaining);
numbytes = remaining;
}
line.drain( );
}
finally { // Always relinquish the resources we use
if (line != null) line.close( );
if (ain != null) ain.close( );
}
}
and give me an exception
Exception in thread "main" javax.sound.sampled.UnsupportedAudioFileException: could not get audio
input stream from input stream
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at test.PlaySoundStream.streamSampledAudio(PlaySoundStream.java:40)
at test.PlaySoundStream.main(PlaySoundStream.java:21)
can help me to solve the exception
or tell me about away can stream by it from shoutcast
I try this code to download MP3 from shoutcast and then you can play sound
public class DownloadMP3 {
private boolean halt = false;
public static final String DEFAULT_HOST = "127.0.0.1";
protected String host = "url";
public static final int DEFAULT_PORT = 80;
protected int port = 8568;
public static final int DEFAULT_TOTAL_SIZE = 0;
protected long totalSize = 0L;
public static final int DEFAULT_CHUNK_SIZE = 0;
long chunkSize = 0L;
public static final String DEFAULT_OUTPUT_DIRECTORY = ".";
File outputDirectory = new File("D:\\");
public static void main(String[ ] args) throws Exception {
DownloadMP3 d = new DownloadMP3();
d.run();
}
public void run()
{
Socket localSocket = null;
PrintWriter localPrintWriter = null;
BufferedInputStream localBufferedInputStream = null;
FileOutputStream localFileOutputStream = null;
try
{
writeMessage("Opening connection to " + this.host + ":" + this.port);
localSocket = new Socket(this.host, this.port);
localPrintWriter = new PrintWriter(localSocket.getOutputStream(), true);
localBufferedInputStream = new BufferedInputStream(localSocket.getInputStream());
localPrintWriter.print("GET / HTTP/1.0\r\n\r\n");
localPrintWriter.flush();
byte[] arrayOfByte = new byte[1024];
long l1 = 0L;
long l2 = 0L;
int i = 1;
File localFile = null;
writeMessage("Host contacted, waiting for response...");
try
{
int k = 0;
int m;
writeMessage("Recieving Data....");
int j;
while ((j = localBufferedInputStream.read(arrayOfByte)) != -1) {
if ((localFileOutputStream == null) || ((this.chunkSize > 0L) && (l2 + j >= this.chunkSize))) {
m = findSync(arrayOfByte, 0, j);
if (m == -1) {
m = j;
}
if (localFileOutputStream != null)
{
localFileOutputStream.write(arrayOfByte, 0, m);
}
if (localFileOutputStream != null) {
localFileOutputStream.close();
}
while ((localFile = new File(this.outputDirectory, this.host + '-' + this.port + '-' + formatFileNum(i++) + ".mp3")).exists());
writeMessage("Saving to file: " + localFile);
localFileOutputStream = new FileOutputStream(localFile);
l2 = 0L;
localFileOutputStream.write(arrayOfByte, m, j - m);
l2 += j - m;
} else {
localFileOutputStream.write(arrayOfByte, 0, j);
l2 += j;
}
if ((this.totalSize > 0L) && (l1 >= this.totalSize)) {
writeMessage("Capture completed successfully.");
if (this.halt) {
writeMessage("Capture interruted.");
}
}
writeErrorMessage("Connection closed by host.");
return;
} catch (IOException localIOException2) {
if (this.halt)
writeMessage("Capture interruted.");
else {
writeErrorMessage(localIOException2.getMessage());
}
} finally {
if (localFileOutputStream != null)
localFileOutputStream.close();
}
}
catch (UnknownHostException localUnknownHostException) {
writeErrorMessage("Unknown host: " + this.host);
return;
} catch (IOException localIOException1) {
writeErrorMessage("Could not connect to " + this.host + " on port " + this.port);
}
finally {
if (localPrintWriter != null) {
localPrintWriter.close();
}
if (localBufferedInputStream != null)
try {
localBufferedInputStream.close();
}
catch (IOException localIOException3) {
}
if (localSocket != null)
try {
localSocket.close();
}
catch (IOException localIOException4)
{
}
}
}
private static int findSync(byte[] paramArrayOfByte, int paramInt1, int paramInt2)
{
for (int i = paramInt1; i < paramInt2 - 1; i++) {
if (((paramArrayOfByte[i] & 0xFF) == 255) && ((paramArrayOfByte[(i + 1)] & 0xE0) == 224)) {
return i;
}
}
return -1;
}
private static String formatFileNum(int paramInt)
{
if (paramInt < 10)
return "00" + paramInt;
if (paramInt < 100) {
return "0" + paramInt;
}
return "" + paramInt;
}
protected void writeMessage(String paramString)
{
System.out.println(paramString);
}
protected void writeErrorMessage(String paramString)
{
System.err.println(paramString);
}
}
I want to read file in opposite direction from end to the start my file,
[1322110800] LOG ROTATION: DAILY
[1322110800] LOG VERSION: 2.0
[1322110800] CURRENT HOST STATE:arsalan.hussain;DOWN;HARD;1;CRITICAL - Host Unreachable (192.168.1.107)
[1322110800] CURRENT HOST STATE: localhost;UP;HARD;1;PING OK - Packet loss = 0%, RTA = 0.06 ms
[1322110800] CURRENT HOST STATE: musewerx-72c7b0;UP;HARD;1;PING OK - Packet loss = 0%, RTA = 0.27 ms
i use code to read it in this way,
String strpath="/var/nagios.log";
FileReader fr = new FileReader(strpath);
BufferedReader br = new BufferedReader(fr);
String ch;
int time=0;
String Conversion="";
do {
ch = br.readLine();
out.print(ch+"<br/>");
} while (ch != null);
fr.close();
I would prefer to read in reverse order using buffer reader
I had the same problem as described here. I want to look at lines in file in reverse order, from the end back to the start (The unix tac command will do it).
However my input files are fairly large so reading the whole file into memory, as in the other examples was not really a workable option for me.
Below is the class I came up with, it does use RandomAccessFile, but does not need any buffers, since it just retains pointers to the file itself, and works with the standard InputStream methods.
It works for my cases, and empty files and a few other things I've tried. Now I don't have Unicode characters or anything fancy, but as long as the lines are delimited by LF, and even if they have a LF + CR it should work.
Basic Usage is :
in = new BufferedReader (new InputStreamReader (new ReverseLineInputStream(file)));
while(true) {
String line = in.readLine();
if (line == null) {
break;
}
System.out.println("X:" + line);
}
Here is the main source:
package www.kosoft.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
public class ReverseLineInputStream extends InputStream {
RandomAccessFile in;
long currentLineStart = -1;
long currentLineEnd = -1;
long currentPos = -1;
long lastPosInFile = -1;
public ReverseLineInputStream(File file) throws FileNotFoundException {
in = new RandomAccessFile(file, "r");
currentLineStart = file.length();
currentLineEnd = file.length();
lastPosInFile = file.length() -1;
currentPos = currentLineEnd;
}
public void findPrevLine() throws IOException {
currentLineEnd = currentLineStart;
// There are no more lines, since we are at the beginning of the file and no lines.
if (currentLineEnd == 0) {
currentLineEnd = -1;
currentLineStart = -1;
currentPos = -1;
return;
}
long filePointer = currentLineStart -1;
while ( true) {
filePointer--;
// we are at start of file so this is the first line in the file.
if (filePointer < 0) {
break;
}
in.seek(filePointer);
int readByte = in.readByte();
// We ignore last LF in file. search back to find the previous LF.
if (readByte == 0xA && filePointer != lastPosInFile ) {
break;
}
}
// we want to start at pointer +1 so we are after the LF we found or at 0 the start of the file.
currentLineStart = filePointer + 1;
currentPos = currentLineStart;
}
public int read() throws IOException {
if (currentPos < currentLineEnd ) {
in.seek(currentPos++);
int readByte = in.readByte();
return readByte;
}
else if (currentPos < 0) {
return -1;
}
else {
findPrevLine();
return read();
}
}
}
Apache Commons IO has the ReversedLinesFileReader class for this now (well, since version 2.2).
So your code could be:
String strpath="/var/nagios.log";
ReversedLinesFileReader fr = new ReversedLinesFileReader(new File(strpath));
String ch;
int time=0;
String Conversion="";
do {
ch = fr.readLine();
out.print(ch+"<br/>");
} while (ch != null);
fr.close();
The ReverseLineInputStream posted above is exactly what I was looking for. The files I am reading are large and cannot be buffered.
There are a couple of bugs:
File is not closed
if the last line is not terminated the last 2 lines are returned on the first read.
Here is the corrected code:
package www.kosoft.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
public class ReverseLineInputStream extends InputStream {
RandomAccessFile in;
long currentLineStart = -1;
long currentLineEnd = -1;
long currentPos = -1;
long lastPosInFile = -1;
int lastChar = -1;
public ReverseLineInputStream(File file) throws FileNotFoundException {
in = new RandomAccessFile(file, "r");
currentLineStart = file.length();
currentLineEnd = file.length();
lastPosInFile = file.length() -1;
currentPos = currentLineEnd;
}
private void findPrevLine() throws IOException {
if (lastChar == -1) {
in.seek(lastPosInFile);
lastChar = in.readByte();
}
currentLineEnd = currentLineStart;
// There are no more lines, since we are at the beginning of the file and no lines.
if (currentLineEnd == 0) {
currentLineEnd = -1;
currentLineStart = -1;
currentPos = -1;
return;
}
long filePointer = currentLineStart -1;
while ( true) {
filePointer--;
// we are at start of file so this is the first line in the file.
if (filePointer < 0) {
break;
}
in.seek(filePointer);
int readByte = in.readByte();
// We ignore last LF in file. search back to find the previous LF.
if (readByte == 0xA && filePointer != lastPosInFile ) {
break;
}
}
// we want to start at pointer +1 so we are after the LF we found or at 0 the start of the file.
currentLineStart = filePointer + 1;
currentPos = currentLineStart;
}
public int read() throws IOException {
if (currentPos < currentLineEnd ) {
in.seek(currentPos++);
int readByte = in.readByte();
return readByte;
} else if (currentPos > lastPosInFile && currentLineStart < currentLineEnd) {
// last line in file (first returned)
findPrevLine();
if (lastChar != '\n' && lastChar != '\r') {
// last line is not terminated
return '\n';
} else {
return read();
}
} else if (currentPos < 0) {
return -1;
} else {
findPrevLine();
return read();
}
}
#Override
public void close() throws IOException {
if (in != null) {
in.close();
in = null;
}
}
}
The proposed ReverseLineInputStream works really slow when you try to read thousands of lines. At my PC Intel Core i7 on SSD drive it was about 60k lines in 80 seconds. Here is the inspired optimized version with buffered reading (opposed to one-byte-at-a-time reading in ReverseLineInputStream). 60k lines log file is read in 400 milliseconds:
public class FastReverseLineInputStream extends InputStream {
private static final int MAX_LINE_BYTES = 1024 * 1024;
private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;
private RandomAccessFile in;
private long currentFilePos;
private int bufferSize;
private byte[] buffer;
private int currentBufferPos;
private int maxLineBytes;
private byte[] currentLine;
private int currentLineWritePos = 0;
private int currentLineReadPos = 0;
private boolean lineBuffered = false;
public ReverseLineInputStream(File file) throws IOException {
this(file, DEFAULT_BUFFER_SIZE, MAX_LINE_BYTES);
}
public ReverseLineInputStream(File file, int bufferSize, int maxLineBytes) throws IOException {
this.maxLineBytes = maxLineBytes;
in = new RandomAccessFile(file, "r");
currentFilePos = file.length() - 1;
in.seek(currentFilePos);
if (in.readByte() == 0xA) {
currentFilePos--;
}
currentLine = new byte[maxLineBytes];
currentLine[0] = 0xA;
this.bufferSize = bufferSize;
buffer = new byte[bufferSize];
fillBuffer();
fillLineBuffer();
}
#Override
public int read() throws IOException {
if (currentFilePos <= 0 && currentBufferPos < 0 && currentLineReadPos < 0) {
return -1;
}
if (!lineBuffered) {
fillLineBuffer();
}
if (lineBuffered) {
if (currentLineReadPos == 0) {
lineBuffered = false;
}
return currentLine[currentLineReadPos--];
}
return 0;
}
private void fillBuffer() throws IOException {
if (currentFilePos < 0) {
return;
}
if (currentFilePos < bufferSize) {
in.seek(0);
in.read(buffer);
currentBufferPos = (int) currentFilePos;
currentFilePos = -1;
} else {
in.seek(currentFilePos);
in.read(buffer);
currentBufferPos = bufferSize - 1;
currentFilePos = currentFilePos - bufferSize;
}
}
private void fillLineBuffer() throws IOException {
currentLineWritePos = 1;
while (true) {
// we've read all the buffer - need to fill it again
if (currentBufferPos < 0) {
fillBuffer();
// nothing was buffered - we reached the beginning of a file
if (currentBufferPos < 0) {
currentLineReadPos = currentLineWritePos - 1;
lineBuffered = true;
return;
}
}
byte b = buffer[currentBufferPos--];
// \n is found - line fully buffered
if (b == 0xA) {
currentLineReadPos = currentLineWritePos - 1;
lineBuffered = true;
break;
// just ignore \r for now
} else if (b == 0xD) {
continue;
} else {
if (currentLineWritePos == maxLineBytes) {
throw new IOException("file has a line exceeding " + maxLineBytes
+ " bytes; use constructor to pickup bigger line buffer");
}
// write the current line bytes in reverse order - reading from
// the end will produce the correct line
currentLine[currentLineWritePos++] = b;
}
}
}}
#Test
public void readAndPrintInReverseOrder() throws IOException {
String path = "src/misctests/test.txt";
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(path));
Stack<String> lines = new Stack<String>();
String line = br.readLine();
while(line != null) {
lines.push(line);
line = br.readLine();
}
while(! lines.empty()) {
System.out.println(lines.pop());
}
} finally {
if(br != null) {
try {
br.close();
} catch(IOException e) {
// can't help it
}
}
}
}
Note that this code reads the hole file into memory and then starts printing it. This is the only way you can do it with a buffered reader or anry other reader that does not support seeking. You have to keep this in mind, in your case you want to read a log file, log files can be very big!
If you want to read line by line and print on the fly then you have no other alternative than using a reader that support seeking such as java.io.RandomAccessFile and this anything but trivial.
As far as I understand, you try to read backwards line by line.
Suppose this is the file you try to read:
line1
line2
line3
And you want to write it to the output stream of the servlet as follows:
line3
line2
line1
Following code might be helpful in this case:
List<String> tmp = new ArrayList<String>();
do {
ch = br.readLine();
tmp.add(ch);
out.print(ch+"<br/>");
} while (ch != null);
for(int i=tmp.size()-1;i>=0;i--) {
out.print(tmp.get(i)+"<br/>");
}
I had a problem with your solution #dpetruha because of this:
Does RandomAccessFile.read() from local file guarantee that exact number of bytes will be read?
Here is my solution: (changed only fillBuffer)
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
public class ReverseLineInputStream extends InputStream {
private static final int MAX_LINE_BYTES = 1024 * 1024;
private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;
private RandomAccessFile in;
private long currentFilePos;
private int bufferSize;
private byte[] buffer;
private int currentBufferPos;
private int maxLineBytes;
private byte[] currentLine;
private int currentLineWritePos = 0;
private int currentLineReadPos = 0;
private boolean lineBuffered = false;
public ReverseLineInputStream(File file) throws IOException {
this(file, DEFAULT_BUFFER_SIZE, MAX_LINE_BYTES);
}
public ReverseLineInputStream(File file, int bufferSize, int maxLineBytes) throws IOException {
this.maxLineBytes = maxLineBytes;
in = new RandomAccessFile(file, "r");
currentFilePos = file.length() - 1;
in.seek(currentFilePos);
if (in.readByte() == 0xA) {
currentFilePos--;
}
currentLine = new byte[maxLineBytes];
currentLine[0] = 0xA;
this.bufferSize = bufferSize;
buffer = new byte[bufferSize];
fillBuffer();
fillLineBuffer();
}
#Override
public int read() throws IOException {
if (currentFilePos <= 0 && currentBufferPos < 0 && currentLineReadPos < 0) {
return -1;
}
if (!lineBuffered) {
fillLineBuffer();
}
if (lineBuffered) {
if (currentLineReadPos == 0) {
lineBuffered = false;
}
return currentLine[currentLineReadPos--];
}
return 0;
}
private void fillBuffer() throws IOException {
if (currentFilePos < 0) {
return;
}
if (currentFilePos < bufferSize) {
in.seek(0);
buffer = new byte[(int) currentFilePos + 1];
in.readFully(buffer);
currentBufferPos = (int) currentFilePos;
currentFilePos = -1;
} else {
in.seek(currentFilePos - buffer.length);
in.readFully(buffer);
currentBufferPos = bufferSize - 1;
currentFilePos = currentFilePos - bufferSize;
}
}
private void fillLineBuffer() throws IOException {
currentLineWritePos = 1;
while (true) {
// we've read all the buffer - need to fill it again
if (currentBufferPos < 0) {
fillBuffer();
// nothing was buffered - we reached the beginning of a file
if (currentBufferPos < 0) {
currentLineReadPos = currentLineWritePos - 1;
lineBuffered = true;
return;
}
}
byte b = buffer[currentBufferPos--];
// \n is found - line fully buffered
if (b == 0xA) {
currentLineReadPos = currentLineWritePos - 1;
lineBuffered = true;
break;
// just ignore \r for now
} else if (b == 0xD) {
continue;
} else {
if (currentLineWritePos == maxLineBytes) {
throw new IOException("file has a line exceeding " + maxLineBytes
+ " bytes; use constructor to pickup bigger line buffer");
}
// write the current line bytes in reverse order - reading from
// the end will produce the correct line
currentLine[currentLineWritePos++] = b;
}
}
}
}