8

I'm using getClass().getResourceAsStream(path) to read from bundle resources.

How can I know the file size before reading the entire stream?

I can't access them with getClass().getResource(path).toURI() when it's packaged, so that won't work.

Oscar Broman
  • 1,109
  • 8
  • 19
  • 2
    Why is the file size important? If it's in a jar, it's likely to be compressed. – RealSkeptic Dec 18 '15 at 17:29
  • Does `getClass().getResourceAsStream(path).available()` return the correct file size? – Buddy Dec 18 '15 at 18:43
  • @Buddy, no. `"Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream [...] by the next invocation of a method"` – Victor Sergienko Aug 09 '16 at 10:56
  • Granted, `getClass().getResource(path).toURI()` does not work, when the application is packaged, on the other hand, you don’t want a URI, you want the size of the resource, so why do you care whether `.toURI()` works? `getClass().getResource(path).openConnection().getContentLength()` *does* work. – Holger Jul 15 '19 at 12:18

3 Answers3

6

I tried answer to this post Ask for length of a file read from Classpath in java but they marked it as duplicated of your question so i give my answer here!

It's possible to get the size of a simple file using:

File file = new File("C:/Users/roberto/Desktop/bar/file.txt");
long length = file.length();
System.out.println("Length: " + length);

When file.txt is packaged in a jar the .length() will return always 0.
So we need to use JarFile:

JarFile jarFile = new JarFile("C:/Users/roberto/Desktop/bar/foo.jar");
Object size = jarFile.getEntry("file.txt").getSize();
System.out.println("Size: " + size.toString())

You can get the compressed size too:

JarFile jarFile = new JarFile("C:/Users/roberto/Desktop/bar/foo.jar");
Object compressedSize = jarFile.getEntry("file.txt").getCompressedSize();
System.out.println("CompressedSize: " + compressedSize);

It's still possible getting the size of a file packaged in a jar using the jar command:

jar tvf Desktop\bar\foo.jar file.txt

Output will be: 5 Thu Jun 27 17:36:10 CEST 2019 file.txt
where 5 is the size.

You can use it in the code:

Process p = Runtime.getRuntime().exec("jar tvf C:/Users/roberto/Desktop/bar/foo.jar file.txt");
StringWriter writer = new StringWriter();
IOUtils.copy(p.getInputStream(), writer, Charset.defaultCharset());
String jarOutput = writer.toString();  

but jdk is required to run the jar command.

Roberto Manfreda
  • 2,345
  • 3
  • 25
  • 39
0

This question has some specific solutions: How do I list the files inside a JAR file?, specifically, using a FileSystem API since Java 7.

It should work for files in a JAR and unpacked files. I'm not sure it will work for a JAR packed in a WAR, for instance.

Community
  • 1
  • 1
Victor Sergienko
  • 13,115
  • 3
  • 57
  • 91
-1

Naturally you cannot query the total size of a stream, since by definition it does not make the whole file available to you. Think of popping your hand in a river. You have a piece of the stream,but you have to put the entire river in your hand to know the total volume.

In this case, you have to read the entire file as a stream and count the size. Remember you are dealing with classes and resources that may be part of a JAR file or other kind of compressed resource. The classloader does not have to provide a file handle to the resource in this case

stan
  • 4,885
  • 5
  • 49
  • 72
  • 2
    I have a few JS files and a HTML file that I wish to serve with Netty, how would you suggest I bundle those files and allow them to be efficiently served over HTTP? I need the file size for the content-length header. – Oscar Broman Dec 18 '15 at 20:59
  • 7
    The OP is not asking about a stream, he's telling that he's "using getResourceAsStream(path)", but needs to "know file size before reading". While the answer is right about the general `InputStream`, but it's not the question. Resources do have their size on the filesystem or in ZIP header. The fact that this information is not available is a sad shortcoming of the API. – Victor Sergienko Aug 09 '16 at 11:00