I have one problem that is to upload file. It is working perfectly on my computer but fails when deploying to a server.
The system is to browse the file, then the system will zip it before uploading it to the server. When a client browse a file, the server will generate an error that the file is not found. Here is my code:
try {
//This is a code to read a zipfile.
String dir = request.getParameter("dirs");
System.out.println(dir);
String tmp = dir.replace( '\\', '/' );
System.out.println(tmp);
String inFilename = tmp;
// String inFilename = dir;
String outFilename = "c:/sms.zip";
//String outFilename = "/webapps/ROOT/sms.zip";
FileInputStream in = new FileInputStream( inFilename);
ZipOutputStream out = new ZipOutputStream(
new FileOutputStream(outFilename));
// Add ZIP entry to output stream.
out.putNextEntry(new ZipEntry(inFilename));
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
//End of zipping file.
//Start uploading.
SimpleFTP ftp = new SimpleFTP();
// Connect to an FTP server on port 21.
ftp.connect("xxxxx", 21, "xxx", "xxxx");
// Set binary mode.
ftp.bin();
// Change to a new working directory on the FTP server.
ftp.cwd("web");
// Upload some files.
ftp.stor(new File("sms.zip"));
ftp.disconnect();
//finish uploading
out.closeEntry();
out.close();
in.close();
response.sendRedirect("../BakMeClient/success.jsp");
}
catch (IOException e) {
System.out.println(e);
}
String dir is the location of file.
The error message is:
java.io.FileNotFoundException: D:\RELIVA\listmenu.java (The system cannot find the file specified)
Thanks for all your comments. From my observation the problem is this script is run on the server not on the client.
What I mean is let's say you browse the file for example at c:/test.txt. When you click the upload button, the form will send the path to the server and the server will find the path in its own directory and of course it will not find it.
I hope you get the idea what happened. So now: how to made it read the path at the client?
Here is definitely a problem:
// Upload some files.
ftp.stor(new File("sms.zip"));
The archive has been created at c:/sms.zip but you try to read it from the relative file location sms.zip (which is equal to ${JAVA_HOME}/sms.zip if I remember correctly The correct part is in Joachim's comment, thanks!!).
Replace these lines with
// Upload some files.
ftp.stor(new File("c:/sms.zip"));
If this doesn't help, then in addition try closing the ZipOutputStream before you send the file with FTP. There's a chance that the ZIP file has not been created yet on the file system just because the stream is still open.
There's a major misunderstanding here. You're sending local disk file system paths around instead of the actual file contents. Imagine that I am the client and I have a file at c:/passwords.txt and I give the path to you. How would you as being a server ever get its contents?
With new FileInputStream("c:/passwords.txt")? No, that is fortunately not going to happen. It will only work when both the client and server runs at physically same machine, as you have found out.
Uploading files with HTML (regardless of if it's inside a JSP file) is supposed to be done with an <input type="file"> field as follows:
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit">
</form>
This way the file will be sent in the request body. As the standard Servlet API versions up to with 2.5 doesn't support mulipart/form-data requests, you need to parse the request yourself. The best way is to use Apache Commons FileUpload for this. Follow the link and read both the User Guide and Frequently Asked Questions for code examples and tips&tricks. When you're already on Servlet 3.0, then you can just use the Servlet API provided HttpServletRequest#getParts() for this. You can find here an article with code examples about that.
If you actually want to upload a complete folder with files to the server side and you don't want to use multiple <input type="file"> fields for this, then you'll need Applet or SWF for this, because this isn't possible with plain vanilla HTML. In the server side you can parse the request just the same way.
I think, if it is working in your system and not in server, there must be problem with server settings.
Or you can check following things
Need to check path you are working on.
Before uploading, try to list the files in that directory, once you generate ZIP file.
Check for permissions.
Your outFilename must be found in the web. Like: "http://www.sample.com/sms.zip" or the likes..
Related
How to download all files in the file directory when clicking the export or download at the same time?
At present, all the files in the file directory have been obtained, then all the files are placed in the list, and then the stream is written after traversing all the files. However, when importing the second file, it will report cannot reset buffer after response has been committed
The source of the problem is in this code: // response.reset();
Code:
String filePath = "/code/data/";
// Get all file addresses of the directory
List<String> filePathList = getFilePath(filePath);
//Create thread pool
for (String str : filePathList){
download(request, response, str);
}
private void download(HttpServletRequest request,
HttpServletResponse response,String filePath) {
File file = new File(filePath);
//Gets the file name.
String fileName = file.getName();
InputStream fis = null;
try {
fis = new FileInputStream(file);
request.setCharacterEncoding("UTF-8");
String agent = request.getHeader("User-Agent").toUpperCase();
if ((agent.indexOf("MSIE") > 0) || ((agent.indexOf("RV") != - 1) &&
(agent.indexOf("FIREFOX") == -1))) {
fileName = URLEncoder.encode(fileName, "UTF-8");
} else {
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
}
// response.reset();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/force-download");
// Set forced download not to open
response.addHeader("Content-Disposition",
"attachment; filename=" + fileName);
response.setHeader("Content-Length", String.valueOf(file.length()));
byte[] b = new byte[1024];
int len;
while ((len = fis.read(b)) != - 1) {
response.getOutputStream().write(b, 0, len);
}
response.flushBuffer();
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
What are the good solutions Thanks
I have not read your code in detail because the bad formatting makes my head hurt.
However, from a superficial reading, it looks like this server-side code is trying to deliver multiple files in response to a single HTTP request.
AFAIK, that is not possible. The HTTP request / response model does not support this. It certainly does not allow a servlet to:
change response headers after the response output stream has been opened
do anything after the response output stream has been closed.
(Your code appears to be trying to do both of those things!)
So, you have to do it differently. Here are some possibilities:
On the server side, assemble all of the files to be downloaded into (say) a temporary ZIP file and then send that. Leave it to the user to unpack the ZIP file ... or not ... as they want.
This is often the best approach. Imagine how annoyed you would be if a few thousand separate files unexpectedly landed in your web browser's Downloads folder.
As 1. and also do something on the client side to transparently unpack the files from the ZIP and put them in the right place in the client's file system.
The "something" could be custom javascript embedded in the web page, or a custom client implemented in Java ... or any other language. (But in the former case, there may be a security issue in allowing sandboxed javascript to write files in arbitrary places without the user confirming each file ... tedious.)
You might be able to send a "multipart" document as the response. However from what I have read, most browsers don't support multipart for downloads; e.g. some browsers will discard all but the last part. (Note: multipart is not designed for this purpose ...)
Change things so that an HTTP request only downloads one file at a time from the directory, and add some client-side stuff to 1) fetch a list of files from the server and iterate the list, fetching each file.
See also: Download multiple files with a single action
This problem I am facing in title is very similar to this question previously raised here (Azure storage: Uploaded files with size zero bytes), but it was for .NET and the context for my Java scenario is that I am uploading small-size CSV files on a daily basis (about less than 5 Kb per file). In addition the API code uses the latest version of Azure API that I am using in contrast against the 2010 used by the other question.
I couldn't figure out where have I missed out, but the other alternative is to do it in File Storage, but of course the blob approach was recommended by a few of my peers.
So far, I have mostly based my code on uploading a file as a block of blob on the sample that was shown in the Azure Samples git [page] (https://github.com/Azure-Samples/storage-blob-java-getting-started/blob/master/src/BlobBasics.java). I have already done the container setup and file renaming steps, which isn't a problem, but after uploading, the size of the file at the blob storage container on my Azure domain shows 0 bytes.
I've tried alternating in converting the file into FileInputStream and upload it as a stream but it still produces the same manner.
fileName=event.getFilename(); //fileName is e.g eod1234.csv
String tempdir = System.getProperty("java.io.tmpdir");
file= new File(tempdir+File.separator+fileName); //
try {
PipedOutputStream pos = new PipedOutputStream();
stream= new PipedInputStream(pos);
buffer = new byte[stream.available()];
stream.read(buffer);
FileInputStream fils = new FileInputStream(file);
int content = 0;
while((content = fils.read()) != -1){
System.out.println((char)content);
}
//Outputstream was written as a test previously but didn't work
OutputStream outStream = new FileOutputStream(file);
outStream.write(buffer);
outStream.close();
// container name is "testing1"
CloudBlockBlob blob = container.getBlockBlobReference(fileName);
if(fileName.length() > 0){
blob.upload(fils,file.length()); //this is testing with fileInputStream
blob.uploadFromFile(fileName); //preferred, just upload from file
}
}
There are no error messages shown, just we know that the file touches the blob storage and shows a size 0 bytes. It's a one-way process by only uploading CSV-format files. At the blob container, it should be showing those uploaded files a size of 1-5 KBs each.
Instead of blob.uploadFromFile(fileName); you should use blob.uploadFromFile(file.getAbsolutePath()); because uploadFromFile method requires absolute path. And you don't need the blob.upload(fils,file.length());.
Refer to Microsoft Docs: https://learn.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-java#upload-blobs-to-the-container
The Azure team replied to a same query I've put on mail and I have confirmed that the problem was not on the API, but due to the Upload component in Vaadin which has a different behavior than usual (https://vaadin.com/blog/uploads-and-downloads-inputs-and-outputs). Either the CloudBlockBlob or the BlobContainerUrl approach works.
The out-of-the-box Upload component requires manual implementation of the FileOutputStream to a temporary object unlike the usual servlet object that is seen everywhere. Since there was limited time, I used one of their addons, EasyUpload, because it had Viritin UploadFileHandler incorporated into it instead of figuring out how to stream the object from scratch. Had there been more time, I would definitely try out the MultiFileUpload addon, which has additional interesting stuff, in my sandbox workspace.
I had this same problem working with .png (copied from multipart files) files I was doing this:
File file = new File(multipartFile.getOriginalFilename());
and the blobs on Azure were 0bytes but when I changed to this:
File file = new File("C://uploads//"+multipartFile.getOriginalFilename());
it started saving the files properly
I want to be able to play audio files from my Java based web application
Now its possible if the file physically sits in a folder below the root folder of my web application
<audio controls="controls">
<source src="/musicserver/test.mp3">
</audio>
but not if it is somewhere else on the machine, I got round this using a symbolic link but this caused another issue that means I cannot use this approach.
So another solution suggested was to instead call a playmusic endpoint passing it the file path as a parameter. like this.
<audio controls="controls">
<source src="/musicserver/playmusic?url=/musicfolder/test.mp3">
</audio>
But I dont know what this endpoint should actually do. The server is written in Java and I can read the file okay, but what should it actually return to allow audio controls to play the music.
First set the response mime type to audio/mpeg, read the mp3 file as raw bytes, basically any servlet response beside xml/json/html you want to write byte[] to response stream.
res.setContentType("audio/mpeg");
//this whole block should be in a try catch
FileInputStream fis = new FileInputStream(new File("yourmp3file.mp3"));
int c;
while((c=fis.read())!=-1){
res.getWriter().write(c);
}
res.getWriter().flush();
I have deployed my application in Apache Tomcat.
I have a folder(assets) to save the files. So want to write a file inside webapps/assets
I tried the following code for that
private String uploadedFiles(MultipartFile files) throws IOException {
String filePath = "../assets/users/image/" + files.getOriginalFilename();
File file = new File(filePath);
byte[] bytes = file.getBytes();
FileOutputStream out = new FileOutputStream(file);
out.write(bytes);
out.close();
But i am getting java.io.FileNotFoundException: ../assets/myfile.jpg (The system cannot find the path specified)
How can save this file?
Note: I want this kind of folder structure. Since I will save "../assets/myfile.png" in the database to access from the client application deployed in the same server.
You can get the tomcat home path with
System.getProperty( "catalina.base" );
You can then add to this your path, in your case /webapps/assets
Hope this helps :)
Maybe I am wrong, but you should give bytes from Multipart files !
And such of kind
../assets/users/image/
is wrong. I think, you should start with root folder, or use Paths.get() nio.
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application