File privateKeyFile = new File(this.getClass().getClassLoader().getResource("privateKey").getFile());
successfully gives me a keyFile. If I now list the path with:
privateKeyFile.toPath()
debug successfully shows me a path to the file:
file:/Users/me/.m2/repository/com/xx/xyz/abc/encryption/1.0/encryption-1.0.jar!/privateKey
--
However, as soon as I try and read that file with
Files.readAllBytes(privateKeyFile.toPath())
I get
Method threw 'java.nio.file.NoSuchFileException' exception.
This is really confusing, and I've tried changing the getResource() to various things like getResource("/privateKey"); - yet that errors a lot sooner, actually a NPE right when trying to create a new File(), so the file MUST exist as I've shown above??
Thanks to replies, I now use this code successfully
//working
InputStream publicKeyStream = this.getClass().getClassLoader().getResourceAsStream("publicKey");
toByteArray(privateKeyStream));
I initally tried the other method that was given, but that resulted in a BadPaddingException, likely due to not fully reading the file
//The incorrect code:
byte[] array = new byte[in.available()];
in.read(array);
The constructor of File does not care if the path string actually points to an existing file, so do not rely on that to check whether the file is there or not. Use privateKeyFile.exists() instead (it returns true if the file exists). From what I see, the file really isn't there or the path you give isn't correct, so exists() should return false.
Since the file is inside of your Jar, it is not recognized by Java as an actual "file". Because of this, you have to read it a little differently. According to this post, you might read it something like this:
InputStream in = getClass().getResourceAsStream("privatekey");
byte[] array = new byte[in.available()];
in.read(array);
Or of you're in Java 9+, it could look like this:
InputStream in = getClass().getResourceAsStream("privatekey");
byte[] array = in.readAllBytes();
Edit:
Since some people wanted an example with the entire source code of the read function, here you go:
InputStream in = getClass().getResourceAsStream("privatekey");
List<Byte> bytes = new ArrayList<Byte>();
while(in.available() > 0) {
byte[] b = new byte[in.available()];
in.read(b);
bytes.addAll(b);
}
byte[] array = (byte[]) bytes.toArray();
Related
I have created a program in Java that I want packaged into an executable jar file. I want this program to take images from the jar file and display them. I created an abstract class with a method to take a String filename and return an Image object. However, when I try to run this method, it fails and produces an "IOException: Stream closed" error.
I can't find anything on why the stream is closed. I don't have any other input streams in my program, as far as I know. Using the method in a new main with nothing but a JFrame set-up still produces the same error.
Whether I call the image file only by its name (i.e. "example.png") or use its relative path (i.e. "/src/icons/example.png"), OR use its absolute path (i.e. "C:/Users/My_Name/Desktop/EXAMPLE/src/icons/example.png") I receive the same stream closed error.
public static Image importImage(String fileName) throws IOException {
Image img = null;
byte[] data = new byte[10000];
BufferedInputStream bis = new BufferedInputStream( Thread.currentThread().getClass().getResourceAsStream(fileName));
int byteRead = bis.read(data, 0, 10000);
img = Toolkit.getDefaultToolkit().createImage(data);
return img;
}
I expect the program to accept the name of the image file in question, and return an Image object. The image file is on the project's classpath, and should be visible.
Okay. So as it turns out, a method like this has two requirements: One, you have to call 'thisClassName.class.getResourceAsStream(fileName).' Exactly like that. You also need to have your fileName start with '/' or it will completely not work. But, as long as the resources you are looking for are included in your program's classpath, it should work from there.
I am trying to open a file for reading or create the file if it was not there.
I use this code:
String location = "/test1/test2/test3/";
new File(location).mkdirs();
location += "fileName.properties";
Path confDir = Paths.get(location);
InputStream in = Files.newInputStream(confDir, StandardOpenOption.CREATE);
in.close();
And I get java.nio.file.NoSuchFileException
Considering that I am using StandardOpenOption.CREATE option, the file should be created if it is not there.
Any idea why I am getting this exception?
It seems that you want one of two quite separate things to happen:
If the file exists, read it; or
If the file does not exist, create it.
The two things are mutually exclusive but you seem to have confusingly merged them. If the file did not exist and you've just created it, there's no point in reading it. So keep the two things separate:
Path confDir = Paths.get("/test1/test2/test3");
Files.createDirectories(confDir);
Path confFile = confDir.resolve("filename.properties");
if (Files.exists(confFile))
try (InputStream in = Files.newInputStream(confFile)) {
// Use the InputStream...
}
else
Files.createFile(confFile);
Notice also that it's better to use "try-with-resources" instead of manually closing the InputStream.
Accordingly to the JavaDocs you should have used newOutputStream() method instead, and then you will create the file:
OutputStream out = Files.newOutputStream(confDir, StandardOpenOption.CREATE);
out.close();
JavaDocs:
// Opens a file, returning an input stream to read from the file.
static InputStream newInputStream(Path path, OpenOption... options)
// Opens or creates a file, returning an output stream that
// may be used to write bytes to the file.
static OutputStream newOutputStream(Path path, OpenOption... options)
The explanation is that OpenOption constants usage relies on wether you are going to use it within a write(output) stream or a read(input) stream. This explains why OpenOption.CREATE only works deliberatery with the OutputStream but not with InputStream.
NOTE: I agree with #EJP, you should take a look to Oracle's tutorials to create files properly.
I think you intended to create an OutputStream (for writing to) instead of an InputStream (which is for reading)
Another handy way of creating an empty file is using apache-commons FileUtils like this
FileUtils.touch(new File("/test1/test2/test3/fileName.properties"));
I've googled around for quite a while for this, but all the results point to pre-Java 7 NIO solutions. I've used the NIO stuff to read in files from the a specific place on the file system, and it was so much easier than before (Files.readAllBytes(path)). Now, I'm wanting to read in a file that is packaged in my WAR and on the classpath. We currently do that with code similar to the following:
Input inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
/* iterate through the input stream to get all the bytes (no way to reliably find the size of the
* file behind the inputStream (see http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#available()))
*/
int byteInt = -1;
try
{
byteInt = inputStream.read();
while (byteInt != -1)
{
byteStream.write(byteInt);
byteInt = inputStream.read();
}
byteArray = byteStream.toByteArray();
inputStream.close();
return byteArray;
}
catch (IOException e)
{
//...
}
While this works, I was hoping there was an easier/better way to do this with the NIO stuff in Java 7. I'm guessing I'll need to get a Path object that represents this path on the classpath, but I'm not sure how to do that.
I apologize if this is some super easy thing to do. I just cannot figure it out. Thanks for the help.
This works for me.
import java.nio.file.Files;
import java.nio.file.Paths;
// fileName: foo.txt which lives under src/main/resources
public String readFileFromClasspath(final String fileName) throws IOException, URISyntaxException {
return new String(Files.readAllBytes(
Paths.get(getClass().getClassLoader()
.getResource(fileName)
.toURI())));
}
A Path represents a file on the file system. It doesn't help to read a resource from the classpath. What you're looking after is a helper method that reads everything fro a stream (more efficiently than how you're doing) and writes it to a byte array. Apache commons-io or Guava can help you with that. For example with Guava:
byte[] array =
ByteStreams.toByteArray(this.getClass().getClassLoader().getResourceAsStream(resourceName));
If you don't want to add Guava or commons-io to your dependencies just for that, you can always read their source code and duplicate it to your own helper method.
As far as I understand, what you want is to open a ReadableByteChannel to your resource, so you can use NIO for reading it.
This should be a good start,
// Opens a resource from the current class' defining class loader
InputStream istream = getClass().getResourceAsStream("/filename.txt");
// Create a NIO ReadableByteChannel from the stream
ReadableByteChannel channel = java.nio.channels.Channels.newChannel(istream);
You should look at ClassLoader.getResource(). This returns a URL which represents the resource. If it's local to the file system, it will be a file:// URL. At that point you can strip off the scheme etc., and then you have the file name with which you can do whatever you want.
However, if it's not a file:// path, then you can fall back to the normal InputStream.
I'm reading a bunch of files from an FTP. Then I need to unzip those files and write them to a fileshare.
I don't want to write the files first and then read them back and unzip them. I want to do it all in one go. Is that possible?
This is my code
FTPClient fileclient = new FTPClient();
..
ByteArrayOutputStream out = new ByteArrayOutputStream();
fileclient.retrieveFile(filename, out);
??????? //How do I get my out-stream into a File-object?
File file = new File(?);
ZipFile zipFile = new ZipFile(file,ZipFile.OPEN_READ);
Any ideas?
You should use a ZipInputStream wrapped around the InputStream returned from FTPClient's retrieveFileStream(String remote).
You don't need to create the File object.
If you want to save the file you should pipe the stream directly into a ZipOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(out);
// do whatever with your zip file
If, instead, you want to open the just retrieved file work with the ZipInputStream:
new ZipInputStream(fileClient.retrieveFileStream(String remote));
Just read the doc here and here
I think you want:
ZipInputStream zis = new ZipInputStream( new ByteArrayInputStream( out.toByteArray() ) );
Then read your data from the ZipInputStream.
As others have pointed out, for what you are trying to do, you don't need to write the downloaded ZIP "file" to the file system at all.
Having said that, I'd like to point out a misconception in your question, that is also reflected in some of the answers.
In Java, a File object does no really represent a file at all. Rather, it represents a file name or *path". While this name or path often corresponds to an actual file, this doesn't need to be the case.
This may sound a bit like hair-splitting, but consider this scenario:
File dir = new File("/tmp/foo");
boolean isDirectory = dir.isDirectory();
if (isDirectory) {
// spend a long time computing some result
...
// create an output file in 'dir' containing the result
}
Now if instances of the File class represented objects in the file system, then you'd expect the code that creates the output file to succeed (modulo permissions). But in fact, the create could fail because, something deleted the "/tmp/foo", or replaced it with a regular file.
It must be said that some of the methods on the File class do seem to assume that the File object does correspond to a real filesystem entity. Examples are the methods for getting a file's size or timestamps, or for listing the names in a directory. However, in each case, the method is specified to throw an exception if the actual file does not exist or has the wrong type for the operation requested.
Well, you could just create a FileOutputStream and then write the data from that:
FileOutputStream fos = new FileOutputStream(filename);
try {
out.writeTo(fos);
} finally {
fos.close();
}
Then just create the File object:
File file = new File(filename);
You need to understand that a File object doesn't represent any real data on disk - it's just a filename, effectively. The file doesn't even have to exist. If you want to actually write data, that's what FileOutputStream is for.
EDIT: I've just spotted that you didn't want to write the data out first - but that's what you've got to do, if you're going to pass the file to something that expects a genuine file with data in.
If you don't want to do that, you'll have to use a different API which doesn't expect a file to exist... as per Qwerky's answer.
Just change the ByteArrayOutputStream to a FileOutputStream.
I have a database file in res/raw/ folder. I am calling Resources.openRawResource() with the file name as R.raw.FileName and I get an input stream, but I have an another database file in device, so to copy the contents of that db to the device db I use:
BufferedInputStream bi = new BufferedInputStream(is);
and FileOutputStream, but I get an exception that database file is corrupted. How can I proceed?
I try to read the file using File and FileInputStream and the path as /res/raw/fileName, but that also doesn't work.
Yes, you should be able to use openRawResource to copy a binary across from your raw resource folder to the device.
Based on the example code in the API demos (content/ReadAsset), you should be able to use a variation of the following code snippet to read the db file data.
InputStream ins = getResources().openRawResource(R.raw.my_db_file);
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
int size = 0;
// Read the entire resource into a local byte buffer.
byte[] buffer = new byte[1024];
while((size=ins.read(buffer,0,1024))>=0){
outputStream.write(buffer,0,size);
}
ins.close();
buffer=outputStream.toByteArray();
A copy of your file should now exist in buffer, so you can use a FileOutputStream to save the buffer to a new file.
FileOutputStream fos = new FileOutputStream("mycopy.db");
fos.write(buffer);
fos.close();
InputStream.available has severe limitations and should never be used to determine the length of the content available for streaming.
http://developer.android.com/reference/java/io/FileInputStream.html#available():
"[...]Returns an estimated number of bytes that can be read or skipped without blocking for more input. [...]Note that this method provides such a weak guarantee that it is not very useful in practice."
You have 3 solutions:
Go through the content twice, first just to compute content length, second to actually read the data
Since Android resources are prepared by you, the developer, hardcode its expected length
Put the file in the /asset directory and read it through AssetManager which gives you access to AssetFileDescriptor and its content length methods. This may however give you the UNKNOWN value for length, which isn't that useful.