This question feels very difficult to explain to me but ill do my best.
Currently I have a method that returns an InputStream with a Zip file that i have to add to a main zip file. Problem is when I write something into the OutputStream it overwrites previous written data. I tried using ZipOutputStream with ZipEntries but this recompresses the file and does weird things, so its not a solution. Things that I'm required to use and are not negotiable are:
Retrieving the file with the method that returns an InputStream
Using IOUtils.copy() method to download the file (this may be optional if u have another solution that allows me to download the file through a browser)
This is the code so far:
OutputStream os = null;
InputStream is = null;
try {
os = response.getOutputStream();
for (int i = 0; i < splited.length; i += 6) {
String[] file= //an array with the data to retrieve the file
is = FileManager.downloadFile(args);
int read;
byte[] buffer = new byte[1024];
while (0 < (read = is.read(buffer))) {
os.write(buffer, 0, read);
}
}
} catch (Exception ex) {
//Exception captures
}
response.setHeader("Content-Disposition", "attachment; filename=FileName");
response.setContentType("application/zip");
IOUtils.copy(is, os);
os.close();
is.close();
return forward;
You can use ZipOutputStream wrapping the response's OutputStream but instead of close call finish, and do not call close on the ResponseOutputStream.
You must start with the HTTP headers.
response.setHeader("Content-Disposition", "attachment; filename=FileName");
response.setContentType("application/zip");
try {
ZipOutputStream os = new ZipOutputStream(response.getOutputStream());
for (int i = 0; i < splited.length - 5; i += 6) {
String[] file= //an array with the data to retrieve the file
try (InputStream is = FileManager.downloadFile(args)) {
os.putNextEntry(new ZipEntry(filePath));
is.TransferTo(os);
os.closeEntry();
}
}
os.finish();
} catch (Exception ex) {
//Exception captures
}
return forward;
Since java 9 transferTo copies Input/OutputStreams.
One can also copy a Path with Files.copy(Path, OutputStream) where Path is an URI based generalisation of File, so also URLs might immediately be copied.
Here try-with-resources ensures that every is is closed.
Related
FileInputStream Fread = new FileInputStream("somefilename");
FileOutputStream Fwrite = null;
for (int i = 1; i <= 5; i++)
{
String fileName = "file" + i + ".txt";
Fwrite = new FileOutputStream(fileName);
int c;
while ((c = Fread.read()) != -1)
{
Fwrite.write((char) c);
}
Fwrite.close();
}
Fread.close();
The above code writes only to one file. How to make it work to write the content of one file to multiple files?
FYI: Note that the read() method you used returns a byte, not a char, so calling write((char) c) should have been just write(c).
To write to multiple files in parallel when copying a file, you create a array of output streams for the destination files, then iterate the array to write the data to all of them.
For better performance, you should always do this using a buffer. Writing one byte at a time will not perform well.
public static void copyToMultipleFiles(String inFile, String... outFiles) throws IOException {
OutputStream[] outStreams = new OutputStream[outFiles.length];
try {
for (int i = 0; i < outFiles.length; i++)
outStreams[i] = new FileOutputStream(outFiles[i]);
try (InputStream inStream = new FileInputStream(inFile)) {
byte[] buf = new byte[16384];
for (int len; (len = inStream.read(buf)) > 0; )
for (OutputStream outStream : outStreams)
outStream.write(buf, 0, len);
}
} finally {
for (OutputStream outStream : outStreams)
if (outStream != null)
outStream.close();
}
}
You will have to create multiple instances of FileOutputStream fwrite1, fwrite2, fwrite3, one per each file you want to write to, then, as you read, you simply write to all of them. This is how you achieve it.
Add this line:
Fread.reset();
after Fwrite.close();
And change the first line of code to this:
InputStream Fread = new BufferedInputStream(new FileInputStream("somefilename"));
Fread.mark(0);
The FReadstream gets to the end once and then there is nothing to make it start from the beginning.
To solve this you can:
call to FRead.reset() after each file writing
cache FRead's value somewhere and write to FWrite from this source
create an array / collection of FileOutputStream and write each byte to all of them during iteration
The recommended solution is of course the first one.
Also there are some problems in your code:
You are highly encouraged to use try-with-resouce for Streams as they should be safely closed
You seem to not follow naming conventions which say to name variables in lowerCamelCase
is it possible to write/create an exe file in Java?
I can successfully read it but writing the exact same data that has been read to a new file seems to create some trouble because Windows tell's me it's not supported for my pc anymore.
This is the code I'm using to read the file where path is a String given with the actual path (it's in the .jar itself that's why I'm using ResourceAsStream()):
try {
InputStream inputStream = FileIO.class.getResourceAsStream(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
ArrayList<String> _final = new ArrayList<String>();
String line;
while ((line = reader.readLine()) != null) {
_final.add(line);
}
inputStream.close();
return _final.toArray(new String[_final.size()]);
}catch(Exception e) {
return null;
}
This is the code I'm using to write the file:
public static void writeFileArray(String path, String[] data) {
String filename = path;
try{
FileWriter fileWriter = new FileWriter(filename);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
for(String d : data) {
bufferedWriter.write(d + "\n");
}
bufferedWriter.close();
}
catch(IOException ex){
System.out.println("FileIO failed to write file, IO exception");
}
}
So it doesn't give me any error's or something and the file size of the original .exe and the 'transferred' .exe stays the same, but it doesn't work anymore. Am I just doing it wrong? Did I forget something? Can u even do this with Java?
Btw I'm not that experienced with reading/writing files..
Thanks for considering my request.
I'm going to guess that you're using a Reader when you should be using a raw input stream. Use BufferedInputStream instead of BufferedReader.
BufferedInputStream in = new BufferedInputStream( inputStream );
The problem is that Reader interprets the binary as your local character set instead of the data you want.
Edit: if you need a bigger hint start with this. I just noticed you're using a BufferedWriter too, that won't work either.
try {
InputStream inputStream = FileIO.class.getResourceAsStream(path);
BufferedInputStream in = new BufferedInputStream( inputStream );
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[ 1024 ];
for( int length; ( length = ins.read( bytes ) ) != -1; )
bos.write( bytes, 0, length );
}
inputStream.close();
return bos;
When you are using Java 7 or newer, you should copy a resource to a file using
public static void copyResourceToFile(String resourcePath, String filePath) {
try(InputStream inputStream = FileIO.class.getResourceAsStream(resourcePath)) {
Files.copy(inputStream, Paths.get(filePath));
}
catch(IOException ex){
System.out.println("Copying failed. "+ex.getMessage());
}
}
This construct ensures correct closing of the resources even in the exceptional case and the JRE method ensures correct and efficient copying of the data.
It accepts additional options, e.g. to specify that the target file should be overwritten in case it already exists, you would use
public static void copyResourceToFile(String resourcePath, String filePath) {
try(InputStream inputStream = FileIO.class.getResourceAsStream(resourcePath)) {
Files.copy(inputStream, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);
}
catch(IOException ex){
System.out.println("Copying failed. "+ex.getMessage());
}
}
You are using InputStreams for strings, .exe files are bytes!
Try using a ByteArrayInputStream and ByteArrayOutputStream.
Edit: completing with markspace's answer:
new BufferedInputStream(new ByteArrayInputStream( ... ) )
I want to retrieve file from ftp server, I have also used Apache poi client.retrieveFile() method, but I'm unable to open it which is showing:
excel cannot open file check file extension and file format. check file is not corrupted
Then I used file reader and writer. Below is my code snippet.
public void testFileWriter()
{
try{
FTPFile[] files = client.listFiles("/Ftp1");
for (FTPFile file : files) {
File serverFile = new File("D:/Pondi.xlsx");
if(!serverFile.isFile())
{
serverFile.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(serverFile));
client.enterLocalPassiveMode();
InputStream inputStream = client.retrieveFileStream("/Ftp1/"+ file.getName());
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("Created Reader");
while(reader.read()!=-1)
{
String temp = reader.readLine();
System.out.println(temp);
writer.write(temp);
}
writer.flush();
writer.close();
reader.close();
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
Please help me to resolve this crucial issue.
You have to use an API for working with it. You can't read these files like reading normal text files.
JExcel will be good for your need.
Examples are be available here
For copying files make use of this. Reading the file for copying by the method that you used won't work properly.
Hope will be helpful for you.
If you want to read and copy binary data, you must not use reader.readLine(), because there are no lines in a binary file. Therefore, this attempt will most likely fail.
Copy it like this instead:
int fileNo = 0;
for (FTPFile file : files) {
File serverFile = new File("D:/Pondi_" + fileNo + ".xlsx");
...
InputStream in = client.retrieveFileStream("/Ftp1/"+ file.getName());
OutputStream out = new FileOutputStream(serverFile);
// read and copy binary data
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
in.close();
out.close();
fileNo++;
}
Beside that, consider giving your files a different name that D:/Pondi.xlsx, because otherwise the file gets overridden again and again in the loop. I did this with fileNo.
Is there any way to create a java.io.File object from an java.io.InputStream ?
My requirement is reading the File from a RAR . I am not trying to write a temporary File, I have a file inside RAR archive which I am trying to read.
You need to create new file and copy contents from InputStream to that file:
File file = //...
try(OutputStream outputStream = new FileOutputStream(file)){
IOUtils.copy(inputStream, outputStream);
} catch (FileNotFoundException e) {
// handle exception here
} catch (IOException e) {
// handle exception here
}
I am using convenient IOUtils.copy() to avoid manual copying of streams. Also it has built-in buffering.
In one line :
FileUtils.copyInputStreamToFile(inputStream, file);
(org.apache.commons.io)
Since Java 7, you can do it in one line even without using any external libraries:
Files.copy(inputStream, outputPath, StandardCopyOption.REPLACE_EXISTING);
See the API docs.
Create a temp file first using org.apache.commons.io.
File tempFile = File.createTempFile(prefix, suffix);
tempFile.deleteOnExit();
FileOutputStream out = new FileOutputStream(tempFile);
IOUtils.copy(in, out);
return tempFile;
Easy Java 9 solution with try with resources block
public static void copyInputStreamToFile(InputStream input, File file) {
try (OutputStream output = new FileOutputStream(file)) {
input.transferTo(output);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
java.io.InputStream#transferTo is available since Java 9.
If you do not want to use other libraries, here is a simple function to copy data from an InputStream to an OutputStream.
public static void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
Now, you can easily write an Inputstream into a file by using FileOutputStream-
FileOutputStream out = new FileOutputStream(outFile);
copyStream (inputStream, out);
out.close();
If you are using Java version 7 or higher, you can use try-with-resources to properly close the FileOutputStream. The following code use IOUtils.copy() from commons-io.
public void copyToFile(InputStream inputStream, File file) throws IOException {
try(OutputStream outputStream = new FileOutputStream(file)) {
IOUtils.copy(inputStream, outputStream);
}
}
I am creating a program that will extract a zip and then insert the files into a database, every so often I get the error
java.lang.Exception: java.io.EOFException: Unexpected end of ZLIB input stream
I can not pinpoint the reason for this as the extraction code is pretty much the same as all the other code you can find on the web. My code is as follows:
public void extract(String zipName, InputStream content) throws Exception {
int BUFFER = 2048;
//create the zipinputstream
ZipInputStream zis = new ZipInputStream(content);
//Get the name of the zip
String containerName = zipName;
//container for the zip entry
ZipEntry entry;
// Process each entry
while ((entry = zis.getNextEntry()) != null) {
//get the entry file name
String currentEntry = entry.getName();
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// establish buffer for writing file
byte data[] = new byte[BUFFER];
int currentByte;
// read and write until last byte is encountered
while ((currentByte = zis.read(data, 0, BUFFER)) != -1) {
baos.write(data, 0, currentByte);
}
baos.flush(); //flush the buffer
//this method inserts the file into the database
insertZipEntry(baos.toByteArray());
baos.close();
}
catch (Exception e) {
System.out.println("ERROR WITHIN ZIP " + containerName);
}
}
}
This is probably caused by this JVM bug (JVM-6519463)
I previously has about one or two errors on 1000 randomly created documents, I applied the proposed solution (catch EOFException and do nothing with it) and I have no more errors.
I would say you are occasionally being given truncated Zip files to process. Check upstream.
I had the same exception and the problem was in the compressing method (not extracting). I did not close the ZipOutputStream with zos.closeEntry() after writing to the output stream. Without that, compressing worked well but I got an exception while extracting.
public static byte[] zip(String outputFilename, byte[] output) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos)) {
zos.putNextEntry(new ZipEntry(outputFilename));
zos.write(output, 0, output.length);
zos.closeEntry(); //this line must be here
return baos.toByteArray();
} catch (IOException e) {
//catch exception
}
}
Never attempt to read more bytes than the entry contains. Call ZipEntry.getSize() to get the actual size of the entry, then use this value to keep track of the number of bytes remaining in the entry while reading from it. See below :
try{
...
int bytesLeft = (int)entry.getSize();
while ( bytesLeft>0 && (currentByte=zis.read(data, 0, Math.min(BUFFER, bytesLeft))) != -1) {
...
}
...
}