I am running a standalone java process which writes data to multiple xlsx files in a parent target directory and upon completion, the entire target directory is zipped and uploaded to cloud and a download link is provided to the user. The xlsx file names and the name of the zip file is user defined and not possible to change.
The issue is with the names of the xlsx files created. If the filename selected by the user is Japanese, like
サイン色紙プレゼントCPN_第2.xlsx
the corresponding file that is created in the system is of the form:
??????????CPN_?2?.xlsx
The same files are being uploaded to cloud and user is seeing garbled file names. However, the Japanese name of the zip file is not garbled and is in Japanese only.
Following is the code sample for creating xlsx files:
String fileName = userGivenName + "_" + randomUUID + ".xlsx";
File file = new File(tmpParentDirectoryName, fileName);
FileOutputStream outputStream = new FileOutputStream(file);
workbook.write(outputStream);
In this case the absolute path of the xlsx file created is like :
/tmpDirectoryPath/??????????CPN_?2?_0c6b37ee-97c4-44d4-b80d-dfe5eafe0045.xlsx
Just like above there are multiple xlsx files created in the same tmpDirectory
Upon completion following is the code sample to create zip files and upload to cloud:
File[] files = getFilesInFolder(tmpDirectory);
if (ArrayUtils.isEmpty(files)) {
continue;
}
File zipFile = new File(targetDirectory, compressedFileName);
createZipFile(files, zipFile);
String url = uploadFile(compressedFileName, zipFile);
Following piece of code writes data to zip file:
public static void createZipFile(File[] files, File zipFile) {
if (ArrayUtils.isEmpty(files)) {
return;
}
byte[] buffer = new byte[1024];
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
try {
for (File file : files) {
FileInputStream fis = new FileInputStream(file);
try {
String fileName = URLDecoder.decode(file.getName(), "UTF-8");
ZipEntry zipEntry = new ZipEntry(fileName);
zos.putNextEntry(zipEntry);
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
} finally {
IOUtils.closeQuietly(fis);
}
}
} finally {
IOUtils.closeQuietly(zos);
}
}
The uploaded zip file has the correct Japanese name but the zip entries of the zip file have garbled xlsx filenames.
The standalone java process has following encoding options:
-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
Following is the output of the locale command:
locale
LANG=en_IN.UTF-8
LC_CTYPE="en_IN.UTF-8"
LC_NUMERIC="en_IN.UTF-8"
LC_TIME="en_IN.UTF-8"
LC_COLLATE="en_IN.UTF-8"
LC_MONETARY="en_IN.UTF-8"
LC_MESSAGES="en_IN.UTF-8"
LC_PAPER="en_IN.UTF-8"
LC_NAME="en_IN.UTF-8"
LC_ADDRESS="en_IN.UTF-8"
LC_TELEPHONE="en_IN.UTF-8"
LC_MEASUREMENT="en_IN.UTF-8"
LC_IDENTIFICATION="en_IN.UTF-8"
LC_ALL=
Can someone direct me as to what am I doing wrong here ? I want the same filenames to be uploaded as given by the user.
I was finally able to crack this.
The issue was with the system properties of the mesos slave that was executing the java process.
The process on the slave was started by a mesos master scheduler using a startup script. Due to this the default java locale properties were not being set up properly on the slave.
I added the following line to the start-up script of the slave:
export LANG=en_IN.UTF-8
Upon explicitly adding the locale property to the start-up script, was able to resolve the issue.
Related
I have tried the followings for .txt, .sql, .java with success BUT I can't write file with the extension with .pdf, .jpg, .zip.
File file = new File("d:/myFolder/something.txt");
File file = new File("d:/myFolder/something.sql");
File file = new File("d:/myFolder/something.java");
// Executed Successfully for the above 3 but java.io.FileNotFoundException (Access is denied) show for these files below.
File file = new File("d:/myFolder/something.jpg");
File file = new File("d:/myFolder/something.pdf");
File file = new File("d:/myFolder/something.zip");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(mpf.getBytes());
fos.close();
fos.flush();
} catch (Exception e) {
System.out.println(e.getMessage());
}
Project is being developed using spring MVC on Windows 7 (64 bit).
Perhaps there is an unusual antivirus or similar security product running on your Windows?
If so, either disable the antivirus or configure it to permit these filetypes.
So long as it is enabled, it is actually doing exactly what it is supposed to do by blocking these file-writes.
I'm trying to export a report to Excel. Using POI I'm able to store in to the path (say D:/reports) which I hardcoded in my code.
My requirement is, before the report generation, to ask for the path, the user wants to save the report to. How to achieve this?
You cannot store a file in user's computer without his permission/action.
1)Store your generated file in container (Tomcat's folder).
2)Write the file as response content.
3) Users get's a prompt to select the location to save the file to disk.
4) Delete the generated file after successfully writing to the user's computer.
you can't store the file in users computer.
Convert your workbook to byte array and write the file as response content.
Try the following:
// converting workbook to byte array
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] bytes = null;
try {
workbook.write(outStream);
bytes = outStream.toByteArray();
} finally {
outStream.close();
}
// setting file properties
response.setContentType('application/vnd.ms-excel');
response.setHeader("Content-disposition", "attachment;filename=excelname.xls");
// writing the byte[] to repsonse.
OutputStream out = response.getOutputStream();
out.write(bytes);
out.close();
By using the above code, you don't need save the file in tomcat and User gets a prompt to save the file in his location.
I have just created small jsp file in which I am downloading a jar file from weblogic server that is installed in my computer through eclipse using the following piece of code which I grabbed from net. But when I try the jar file, it says it is corrupt. The sizes of original and downloaded jar files are identical. I can download and open text files using the code. What is wrong in the code?
<%
String filename = "Words2.jar";
String filepath = "C:\\Users\\OD00259\\Desktop\\";
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition","attachment; filename=\"" +
filename + "\"");
java.io.FileInputStream fileInputStream=new java.io.FileInputStream
(filepath + filename);
int i;
while ((i=fileInputStream.read()) != -1) {
out.write(i);
}
fileInputStream.close();
%>
Try Change the content-type to application/java-archive. Also set the content-length header to include the size of the file.
Also, I would recommend you to use some checksum tools like md5sum for verifying the file downloads comparison instead of relying on the size to compare.
I have the following code that writes a text file in a zip:
FileOutputStream fOut = new FileOutputStream(fullFilename, false);
BufferedOutputStream bOut = new BufferedOutputStream(fOut);
ZipOutputStream zOut = new ZipOutputStream(bOut);
zOut.putNextEntry(new ZipEntry("aFile1.txt"));
//Do some processing and write to zOut...
zOut.write(...);
(...)
zOut.closeEntry();
zOut.close();
//Etc (close all resources)
I would need to change the filename of the zipEntry after it has been written (as its name will depend on its content written).
Also, it is not an option to write in a buffer and write to file only when final filename is known (because file size is potentially very large: not enough memory).
Any advice on how to do this would be greatly appreciated!
Thanks,
Thomas
It is a missing functionality, which could have been simple, as the entries themselves are not compressed.
The easiest way, requiring a rewrite though, is the zip FileSystem: since java 7 you may use a zip file as a virtual file system: writing, renaming and moving files in them. An example. You copy a file from the normal file system into the zip file system, and later rename the file in the zip.
// Create the zip file:
URI zipURI = URI.create("jar:file:" + fullFilename); // "jar:file:/.../... .zip"
Map<String, Object> env = new HashMap<>();
env.put("create", "true");
FileSystem zipFS = FileSystems.newFileSystem(zipURI, env, null);
// Write to aFile1.txt:
Path pathInZipfile = zipFS.getPath("/aFile1.txt");
BufferedWriter out = Files.newBufferedWriter(pathInZipfile,
StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);
out.write("Press any key, except both shift keys\n");
out.close();
// Rename file:
Path pathInZipfile2 = zipFS.getPath("/aFile2.txt");
Files.move(pathInZipfile, pathInZipfile2);
zipFS.close();
In principle you could also keep your old code - without renaming. And use a zip file system just for renaming.
How about saving the contents of aFile1.txt to a temporary file on disk, renaming it, and then creating the zip file afterwards? The last step can then be deleting the file you created on disk.
I am trying to use a jar file which itself is a web application in another web project. In my jar which i have created using eclipse's export to jar functionality, I have stored a directory.To access the files the from that directory i am using
BufferdReader tempDir = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(myDirPath),"UTF-8"));
// Then i iterate on tempDir
String line;
ArrayList<File> tempDirList = new ArrayList<File>();
int c = 0;
try {
while((line = tempDir.readLine())!= null)
{
File f = new File(line);
tempDirList.add(f);
c++;
}
} catch (IOException e)
{
e.printStackTrace();
}
Now on itrating on tempDirList when i try to read the file i need file path from which i get file but I did not get file path.
So i want to know that how i get file path?
You cannot access the files in the JAR as File objects since in the web container they might not get unpacked (so there is no file). You can only access them via streams as you did.
getClass().getResourceAsStream(myDirPath + "/file1.txt");
If you really need File objects (most of the times it's quite easy to avoid that), copy the files into temporary files which you then can access.
File tmp = File.createTemp("prefix", ".tmp");
tmp.deleteOnExit();
InputStream is = getClass().getResourceAsStream(myDirPath + "/file1.txt");
OutputStream os = new FileOutputStream(tmp);
ByteStreams.copy(is, os);
os.close();
is.close();
But as I said, using streams instead of file objects in the first place makes you more flexible.
If you really don't know all the files in the directory at compile time you might be interested in this answer to list contents.