How to open a file without saving it to disk - java

My Question: How do I open a file (in the system default [external] program for the file) without saving the file to disk?
My Situation: I have files in my resources and I want to display those without saving them to disk first. For example, I have an xml file and I want to open it on the user's machine in the default program for reading xml file without saving it to the disk first.
What I have been doing: So far I have just saved the file to a temporary location, but I have no way of knowing when they no longer need the file so I don't know when/if to delete it. Here's my SSCCE code for that (well, it's mostly sscce, except for the resource... You'll have to create that on your own):
package main;
import java.io.*;
public class SOQuestion {
public static void main(String[] args) throws IOException {
new SOQuestion().showTemplate();
}
/** Opens the temporary file */
private void showTemplate() throws IOException {
String tempDir = System.getProperty("java.io.tmpdir") + "\\BONotifier\\";
File parentFile = new File(tempDir);
if (!parentFile.exists()) {
parentFile.mkdirs();
}
File outputFile = new File(parentFile, "template.xml");
InputStream inputStream = getClass().getResourceAsStream("/resources/template.xml");
int size = 4096;
try (OutputStream out = new FileOutputStream(outputFile)) {
byte[] buffer = new byte[size];
int length;
while ((length = inputStream.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
inputStream.close();
}
java.awt.Desktop.getDesktop().open(outputFile);
}
}

Because of this line:
String tempDir = System.getProperty("java.io.tmpdir") + "\\BONotifier\\";
I deduce that you're working on Windows. You can easily make this code multiplatform, you know.
The answer to your question is: no. The Desktop class needs to know where the file is in order to invoke the correct program with a parameter. Note that there is no method in that class accepting an InputStream, which could be a solution.
Anyway, I don't see where the problem is: you create a temporary file, then open it in an editor or whatever. That's fine. In Linux, when the application is exited (normally) all its temporary files are deleted. In Windows, the user will need to trigger the temporary files deletion. However, provided you don't have security constraints, I can't understand where the problem is. After all, temporary files are the operating system's concern.

Depending on how portable your application needs to be, there might be no "one fits all" solution to your problem. However, you can help yourself a bit:
At least under Linux, you can use a pipe (|) to direct the output of one program to the input of another. A simple example for that (using the gedit text editor) might be:
echo "hello world" | gedit
This will (for gedit) open up a new editor window and show the contents "hello world" in a new, unsaved document.
The problem with the above is, that this might not be a platform-independent solution. It will work for Linux and probably OS X, but I don't have a Windows installation here to test it.
Also, you'd need to find out the default editor by yourself. This older question and it's linked article give some ideas on how this might work.

I don't understand your question very well. I can see only two possibilities to your question.
Open an existing file, and you wish to operate on its stream but do not want to save any modifications.
Create a file, so that you could use file i/o to operate on the file stream, but you don't wish to save the stream to file.
In either case, your main motivation is to exploit file i/o existingly available to your discretion and programming pleasure, am I correct?
I have feeling that the question is not that simple and this my answer is probably not the answer you seek. However, if my understanding of the question does coincide with your question ...
If you wish to use Stream io, instead of using FileOutputStream or FileInputStream which are consequent to your opening a File object, why not use non-File InputStream or OutputStream? Your file i/o utilities will finally boil down to manipulating i/o streams anyway.
http://docs.oracle.com/javase/7/docs/api/java/io/OutputStream.html
http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html
No need to involve temp files.

Related

How can I open a FileInputStream that has its share set to allow ReadWrite?

In .Net I can open a FileStream set to FileAccess.Read, FileShare.ReadWrite. How can I do the same in Java?
Files.newInoutStream() does not appear to support either of these capabilities.
Update: Let me explain why. We have a common use case where our application opens a DOCX file while Word has it opening for editing. The only way Windows allows this due to the locks Word has on the file is FileAccess.Read & FileShare.ReadWrite.
And yes, that's dangerous (would be fine if it was FileShare.Read). But the world is what it is here and this in practice works great.
But it means I need to find a way in Java to open an InputStream to that file that the existing constraints due to Word holding it open require.
There is no 'InoutStream' in java.
You're probably looking for Files.newByteChannel:
import java.nio.ByteBuffer;
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
class Snippet {
public static void main(String[] args) throws Exception {
Path path = Paths.get("test.txt");
try (var channel = Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.READ)) {
ByteBuffer bb = ByteBuffer.allocate(1024);
channel.read(bb);
// Note that 'read' reads 1 to x bytes depending on file system and
// phase of the moon.
bb.flip();
System.out.println("Read: " + StandardCharsets.UTF_8.decode(bb));
bb.clear();
channel.position(0);
channel.write(StandardCharsets.UTF_8.encode("Hello, World!"));
channel.position(0);
channel.read(bb);
bb.flip();
System.out.println("Read: " + StandardCharsets.UTF_8.decode(bb));
}
}
}
make a file named 'test.txt', put in whatever you like, then run this. It'll print whatever is there, then overwrite it with Hello, World!.
Note that the read call is guaranteed to read at least 1 byte, but will not neccessarily fill the entire buffer even if the file is that large: The idea is that you read one 'block' that the OS and file system can efficiently transfer in one operation. You'll need to add some loops if you want to read a guaranteed minimum, or even the entire file.

How to delete file in Java if locked by a process?

I decided to post a new question on this since none of the existing posts lead to me a solution. Mine is a Spring Boot application and here is the service:
public String fetchPrediction(MultipartFile file) throws IOException, InterruptedException {
File convFile = new File( System.getProperty("user.dir")+"/"+file.getOriginalFilename());
convFile.setWritable(true);
file.transferTo(convFile);
INDArray array = new CustomerLossPrediction().generateOutput(convFile);
Files.delete(Paths.get(convFile.getPath()));
return array.toString();
}
File deletion isn't happening and it gets stored at user home directory:
Found that the file is being used by the Java process. How can I delete this file once execution is completed? Is there a better approach here rather than writing to a file? Some of you would bring up writing to OutputStream here, but note that I need to work with MultipartFile in order to have file upload functionality.
I don't know if that's possible but I think you can rename the file to a randomly generated string then afterwards lock, read, unlock then delete the renamed file. In theory, another program could guess the filename and read the file just after it's unlocked but before it is deleted. But in practice, you'll probably be fine.

Unlock a file opened by Excel, Word, or any program

The code I'm writing in Java is is close a file left open by the user. So, here is what typically happens: a user is editing an Excel file, they save it, leave it open, and then close the lid on their laptop. The file is still kept open and locked so no one else can edit it. Is there a way to kick them off and unlock the file? When they are using the file, it is "checked out." Here is what shows up:
What checked out looks like: (image)
The following code, interfacing through WinDAV with SharePoint, tells me if a file is locked or not (I know it's not great code, but it works and I've tried several other solutions including Filelock, Apache IO, FileStream, etc.):
String fileName = String.valueOf(node);
File file = new File(fileName);
boolean replaced;
File sameFileName = new File(fileName);
if(file.renameTo(new File(sameFileName + "_UNLOCK"))){
replaced = true; //file is currently not in use
(new File(sameFileName + "_UNLOCK")).renameTo(sameFileName);
}else{
replaced = false; //file is currently in use
}
So, how would I unlock a file now? The only other solution is PowerShell using SharePoint libraries, but that has a whole lot of other problems...
As per the post, you can use the tool Handle, which is a CLI tool to find out which process is locking the file. Once you have the process ID, you can kill that process. I'm not aware of any Java API that would identify the culprit process. For killing the process you can use taskkill, and you can call it using Runtime like this. Both the operation require you app to run at Administrator or above privilege.

How to move/rename uploaded file?

I followed this tutorial for uploading a file in my JSF2 application.
The application works fine but I am unhappy with one aspect.
While rebuilding the request, the File sent via request is saved somewhere on the disk.
Even though the file is saved I need to rename the file with a name which is available after entering the Managed Bean containing the action method.
Therefore I decided to create a new file with de desired name, copy the already saved file, and then delete the unneeded one.
private File uploadFile;
//...
try {
BufferedWriter bw = new BufferedWriter(new FileWriter(newFile));
BufferedReader br = new BufferedReader(new FileReader(uploadFile));
String line = "";
while ((line = br.readLine()) != null){
bw.write(line);
}
} catch (Exception e){}
The new file appears in the desired location but this error is thrown when I'm trying to open the file: "Invalid or unsupported PNG file"
These are my questions:
Is there a better way to solve this problem?
Is this solution the best way to upload a picture? Is there a reason to save the file before the business logic when there may be need to resize the picture or the desired name is not available yet.
LE:
I know abot this tutorial as well but I'm trying to do this mojarra only.
There is a rename method built into java.io.File object already, I'd be surprised if it didn't work for your situation.
public boolean renameTo(File dest)
Renames the file denoted by this abstract pathname.
Many aspects of the behavior of this method are inherently platform-dependent:
The rename operation might not be able to move a file from one filesystem to
another, it might not be atomic, and it might not succeed if a file with the
destination abstract pathname already exists. The return value should always
be checked to make sure that the rename operation was successful.
You can also check if a file exists before saving it, and you can use the ImageIO class to do validations on the uploaded file before performing the initial save.
Don't use Reader and Writer when you deal with binary files like images. Use streams: FileInputStream and FileOutputStream. And the best variant is to use #Perception solution with renameTo method.
Readers read file as if it consists of characters (e.g. txt, properties, yaml files). Image files are not characters, they are binary and you must use streams for that.

Java downloading files sometimes result in CRC

I've written code to automatically download a batch of files using an InputStream and a FileOutputStream.
The code is very straightforward:
is = urlConn.getInputStream();
fos = new FileOutputStream(outputFile);
eventBus.fireEvent(this, new DownloadStartedEvent(item));
int read;
byte[] buffer = new byte[2048];
while ((read = is.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
eventBus.fireEvent(this, new DownloadCompletedEvent(item));
At first sight this works very well, files get downloaded without any problems, however,
occasionally while trying to extract a batch of downloaded rar files, extraction fails with one of the rar parts having a CRC error.
As this happened a few times already, although not consistently, I started to suspect that something in this code is not correct/optimal.
It will be helpful to know that there are 4 downloads executing concurrently using the JDK FixedThreadPool mechanism:
execService.execute(new Runnable() {
#Override
public void run() {
if (item.getState().equals(DownloadCandidateState.WAITING)) {
Downloader downloader = new Downloader(eventBus);
downloader.download(item, item.getName());
}
}
});
But because every download thread uses a new instance of the Downloader class, I believe this problem is not a side effect of concurrency?
Any ideas if this occasional CRC error has to do with the code or if it has to do with something else?
UPDATE
I can verify that the file size of a problematic file is correct.
I also did a diff (on linux) on the automatically downloaded file and the manually downloaded file.
The filesize is the exact same for both files, however, diff says that the binary content differs between the 2 files:
Binary files file.rar and file(2).rar differ
UPDATE 2
I used a visual binary diff tool and could see that a sequence of 128 bytes was different, somewhere in the middle of the file. I don't understand how that could happen, as the file being downloaded doesn't change and it is being read byte per byte using an input stream. Any ideas??
You can also use Apache's HttpClient if you don't want to handle that entity streaming yourself. It's a well written and documented library. There are several usable entity / entity wrapper classes available.
Here you can have a look at entity retrieval: http://hc.apache.org/httpcomponents-client-4.0.1/tutorial/html/fundamentals.html#d4e152
You should run a diff (unix tool) comparing the original with the result to find out what has actually changed. You May see a pattern right away.
I would start by flushing (or closing) the FileOutputStream
Your code is correct provided everything is closed and no exceptions are thrown. The problem lies elsewhere, probably in the original files.
Problem seemed to have been the Linux atheros driver for my NIC.

Categories

Resources