I have an object of StreamResource class w/ some needed content in it. I'm sure this content is valid and i need to save it locally for the further processing. Here is the code snippet:
OutputStream os = new FileOutputStream(filePath, false);
byte[] buffer = new byte[1024];
int bytesRead;
//read from is to buffer
try {
while(true)
{
bytesRead = resource.getStream().getStream().read(buffer);
if(bytesRead == -1)
break;
os.write(buffer, 0, bytesRead);
resource.getStream().getStream().skip(bytesRead);
}
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
And here i join the endless loop. Break is never ocured and file in the needed location becomes huge as it should actually. Under debugger i see that read() operation returns only the 1st chunk of bytes in each iteration even w/ skip() call after os.write.
How should i read the content from the stream?
Thanks.
According to the source code of StreamResource a new DownloadStream is created on each call. You should call it only once like in the following snippet:
OutputStream os = new FileOutputStream(filePath, false);
byte[] buffer = new byte[1024];
int bytesRead;
//read from is to buffer
try {
DownloadStream stream = resource.getStream();
while(true)
{
bytesRead = stream.getStream().read(buffer);
if(bytesRead == -1)
break;
os.write(buffer, 0, bytesRead);
}
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
That way the stream will not be read from the beginning on every iteration. However, I still don't get why you use the indirection over StreamResource because I guess you create that object before.
Related
I am trying to read an image and deliver it through a Java socket. But there are some bits that does not fit. When viewing in a diff tool I realized that all numbers bigger than 127 were truncated.
So I wanted to just convert it to a char[] array and return it instead. Now I'm getting a complette different image, perhaps due to char's size.
try (PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename), BUFSIZ)) {
byte[] buffer = new byte[BUFSIZ];
while (in.read(buffer) != -1) {
response.append(new String(buffer));
out.print(response.toString());
response.setLength(0);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
This is my reading and delivering code.
I've read many times to use ImageIO but I want to do it without, since I don't know whether it's an image or not. (And what about other file types like executables?)
So, is there any way to convert it to something like an unsigned byte that'll be delivered correctly on the client? Do I have to use something different than read() to achieve that?
Writers are for character data. Use the OutputStream. And you're making the usual mistake of assuming that read() filled the buffer.
The following loop will copy anything correctly. Memorize it.
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Repeat after me: a char is not a byte and it's not a code point.
Repeat after me: a Writer is not an OutputStream.
try (OutputStream out = this.socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename), BUFSIZ)) {
byte[] buffer = new byte[BUFSIZ];
int len;
while ((len = in.read(buffer))) != -1) {
out.write(buffer, 0, len);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
(this is from memory, check the args for write()).
I can't use ImageIO.read() because of my own restrictions. I can only load bytes after GET request and I need to save this bytes to file as image. But it seems to me, that there also loads some extra data, which browser usually filter (maybe response headers). So I get the array of raw bytes which I even can't open as image.
What should I do with this bytes?
Example:
byte[] buf = ContentLoader.loadBytes(new URL("http://images.visitcanberra.com.au/images/canberra_hero_image.jpg"));
try {
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\image.jpg"));
fileOutputStream.write(buf);
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
loadBytes() method:
public static byte[] loadBytes(URL url) {
ByteArrayOutputStream boutArray = new ByteArrayOutputStream();
try {
URLConnection connection = url.openConnection();
BufferedInputStream bin = new BufferedInputStream(connection.getInputStream());
byte[] buffer = new byte[1024 * 16];
while (bin.read(buffer) != -1) {
boutArray.write(buffer);
boutArray.flush();
}
bin.close();
} catch (Exception e) {
return null;
}
return boutArray.toByteArray();
}
Usual problems. The standard way to copy a stream in Java is:
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
out.close();
in.close();
Note that you need to store the result returned by read() into a variable; that you need to use it in the next write() call; that you shouldn't flush() inside a loop; and that you need to close the input and output streams.
And why you're using a ByteArrayInputStream at all is a mystery. It's just a waste of time and space. Read directly from the URL input stream, and write directly to the FileOutputStream.
The following code works for me:-
URL url = new URL("my url...");
InputStream is = url.openStream();
OutputStream os = new FileOutputStream("img.jpg");
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
Well i am trying to transfer a file using sockets in java
Here is the code
Client Code
try{
// get streams
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream din = new DataInputStream (socket.getInputStream());
dos.writeUTF(fileName);
dos.flush();
boolean isOk = din.readBoolean();
if(!isOk){
throw new StocFileNotFound("Fisierul: " + fileName +" was not found on:" + address.toString());
} else {
baos = new ByteArrayOutputStream();
byte biti [] = new byte[1024];
while(din.read(biti,0,1024) != -1){
baos.write(biti,0,biti.length);
}
}
}
catch(IOException e){}
finally {
try{ socket.close(); } catch (IOException e){}
}
and then I return the baos.toByteArray() and write it to a file with the OutputStream`s write method.
Server code
try{
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream din = new DataInputStream (socket.getInputStream());
// check if it is really a file or if it is an existing file
File file = new File(din.readUTF());
// write false
if ( !file.exists() || !file.isFile() ){
dos.writeBoolean(false);
dos.flush();
}
// write true and write the file
else {
byte biti[] = new byte[1024];
dos.writeBoolean(true);
FileInputStream fis = new FileInputStream(file);
while(fis.read(biti,0,1024) != -1){
dos.write(biti,0,biti.length);
}
dos.flush();
try{ fis.close(); } catch (IOException e){}
}
} catch (IOException e){}
finally {
try{socket.close();}catch(IOException e){}
}
The problem
When i transfer a .txt file and view it in gedit it shows the text followed by multiple \00\00\00, though when i open it using notepad(in wine) it shows only the text. Plus viewing images and .doc works also. So is it something with gedit or is it with my program?
Edit
i was sending something like "hi, hope it works!"
This is the problem (or at least a problem):
while(fis.read(biti,0,1024) != -1)
{
dos.write(biti,0,biti.length);
}
You're always writing out the whole buffer, however many bytes were actually read. You should have:
int bytesRead;
while ((bytesRead = fis.read(biti, 0, 1024)) != -1)
{
dos.write(biti, 0, bytesRead);
}
(You've got the same problem in both bits of code.)
You might want to look at Guava which has various utility methods to relieve you of a lot of the tedium (and possible error) of writing this kind of code over and over again.
The read method will return the actual number of bytes read from the stream. You should use that as a parameter to your write method, or else you will be writing garbage to it.
In TCP i am receiving media stream from an IP camera as RAW. According to there advise, i need to write that as file. And then i can play it with media player such as VLC.
But when i write this to a file, and play with media players it never play corrupted.
After comparing the original file i see my Java writing it in wrong characters. And there sample file shows different. What or how do i fix such file writing issue, here is how i am writing it:
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
bytes_read = sock.getInputStream().read(buf, 0, buf.length);
String data = new String(buf, 0, bytes_read);
System.err.println("DATA: " + bytes_read + " bytes, data=" +data);
BufferedWriter out = new BufferedWriter(
new FileWriter("capture.ogg", true));
out.write(data);
out.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
You shouldn't use Readers, Writers and Strings for binary data. Stick with InputStreams and OutputStreams.
I.e., change
BufferedWriter -> BufferedOutputStream,
FileWriter -> FileOutputStream
and instead of String, just use a byte[].
If you're dealing with sockets, I must advice you to look into the NIO package though.
You're doing it right... at least until the part where you turn your byte[] into a String:
That step only really makes sense if your byte[] represents textual data in the first place! Which it doesn't!
Whenever you handle binary data or don't actually care what the data represents you must avoid using String/Reader/Writer to handle that data. Instead do use byte[]/InputStream/OutputStream.
Also, you must read from the socket in a loop, because nothing guarantees that you've read everything:
byte[] buf=new byte[1024];
int bytes_read;
OutputStream out = new FileOutputStream("capture.ogg", true);
InputStream in = sock.getInputStream();
while ((bytes_read = in.read(buf)) != -1) {
out.write(buf, 0, bytes_read);
}
out.close();
The way you have it written limits the output file to a maximum size of 1024 bytes. Try a loop:
try {
byte[] buf = new byte[1024];
int bytes_read = 0;
InputStream in = sock.getInputStream();
FileOutputStream out = new FileOutputStream(new File("capture.ogg"));
do {
bytes_read = in.read(buf, 0, buf.length);
System.out.println("Just Read: " + bytes_read + " bytes");
if (bytes_read < 0) {
/* Handle EOF however you want */
}
if (bytes_read > 0)
out.write(buf, 0, bytes_read);
} while (bytes_read >= 0);
out.close();
} catch (IOException e) {
e.printStackTrace(System.err);
}
I'm attempting to output a text file to the console with Java. I was wondering what is the most efficient way of doing so?
I've researched several methods however, it's difficult to discern which is the least performance impacted solution.
Outputting a text file to the console would involve reading in each line in the file, then writing it to the console.
Is it better to use:
Buffered Reader with a FileReader, reading in lines and doing a bunch of system.out.println calls?
BufferedReader in = new BufferedReader(new FileReader("C:\\logs\\"));
while (in.readLine() != null) {
System.out.println(blah blah blah);
}
in.close();
Scanner reading each line in the file and doing system.print calls?
while (scanner.hasNextLine()) {
System.out.println(blah blah blah);
}
Thanks.
If all you want to do is print the contents of a file (and don't want to print the next int/double/etc.) to the console then a BufferedReader is fine.
Your code as it is won't produce the result you're after, though. Try this instead:
BufferedReader in = new BufferedReader(new FileReader("C:\\logs\\log001.txt"));
String line = in.readLine();
while(line != null)
{
System.out.println(line);
line = in.readLine();
}
in.close();
I wouldn't get too hung up about it, though because it's more likely that the main bottleneck will be the ability of your console to print the information that Java is sending it.
If you're not interested in the character based data the text file is containing, just stream it "raw" as bytes.
InputStream input = new BufferedInputStream(new FileInputStream("C:/logs.txt"));
byte[] buffer = new byte[8192];
try {
for (int length = 0; (length = input.read(buffer)) != -1;) {
System.out.write(buffer, 0, length);
}
} finally {
input.close();
}
This saves the cost of unnecessarily massaging between bytes and characters and also scanning and splitting on newlines and appending them once again.
As to the performance, you may find this article interesting. According the article, a FileChannel with a 256K byte array which is read through a wrapped ByteBuffer and written directly from the byte array is the fastest way.
FileInputStream input = new FileInputStream("C:/logs.txt");
FileChannel channel = input.getChannel();
byte[] buffer = new byte[256 * 1024];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
try {
for (int length = 0; (length = channel.read(byteBuffer)) != -1;) {
System.out.write(buffer, 0, length);
byteBuffer.clear();
}
} finally {
input.close();
}
If it's a relatively small file, a one-line Java 7+ way to do this is:
System.out.println(new String(Files.readAllBytes(Paths.get("logs.txt"))));
See https://docs.oracle.com/javase/7/docs/api/java/nio/file/package-summary.html for more details.
Cheers!
If all you want is most efficiently dump the file contents to the console with no processing in-between, converting the data into characters and finding line breaks is unnecessary overhead. Instead, you can just read blocks of bytes from the file and write then straight out to System.out:
package toconsole;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) {
BufferedInputStream bis = null;
byte[] buffer = new byte[8192];
int bytesRead = 0;
try {
bis = new BufferedInputStream(new FileInputStream(args[0]));
while ((bytesRead = bis.read(buffer)) != -1) {
System.out.write(buffer, /* start */ 0, /* length */ bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try { bis.close(); } catch (Exception e) { /* meh */ }
}
}
}
In case you haven't come across this kind of idiom before, the statement in the while condition both assigns the result of bis.read to bytesRead and then compares it to -1. So we keep reading bytes into the buffer until we are told that we're at the end of the file. And we use bytesRead in System.out.write to make sure we write only the bytes we've just read, as we can't assume all files are a multiple of 8 kB long!
FileInputStream input = new FileInputStream("D:\\Java\\output.txt");
FileChannel channel = input.getChannel();
byte[] buffer = new byte[256 * 1024];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
try {
for (int length = 0; (length = channel.read(byteBuffer)) != -1;) {
System.out.write(buffer, 0, length);
byteBuffer.clear();
}
} finally {
input.close();
}
Path temp = Files.move
(Paths.get("D:\\\\Java\\\\output.txt"),
Paths.get("E:\\find\\output.txt"));
if(temp != null)
{
System.out.println("File renamed and moved successfully");
}
else
{
System.out.println("Failed to move the file");
}
}
For Java 11 you could use more convenient approach:
Files.copy(Path.of("file.txt"), System.out);
Or for more faster output:
var out = new BufferedOutputStream(System.out);
Files.copy(Path.of("file.txt"), out);
out.flush();