Search code examples
javasmbj

Get exact file size via smbj


I am trying to read files from an SMB share using the smbj library. My code needs to read into a byte array (see below), and I need to know the file size before reading. Unfortunately when studying the code I can only find methods to get the allocated size, which usually is bigger than the real file size.

So how can I get the actual size of the file in bytes?

My (wrong code) so far looks like this:

    SMBClient client = new SMBClient();
    try(Connection connection = client.connect(hostname)) {
      AuthenticationContext ac = new AuthenticationContext(user, password.toCharArray(), domain);
      Session session = connection.authenticate(ac);

      // Connect to Share
      try (DiskShare share = (DiskShare) session.connectShare(shareName)) {
          FileAllInformation fileInfo = share.getFileInformation(path);
          File file = share.openFile(path, EnumSet.of(AccessMask.GENERIC_READ), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OPEN, null);

          long fileSize = fileInfo.getStandardInformation().getAllocationSize();

          // this part is problematic as it throws an IOException
          // if not the fileSize amount of bytes can be read
          byte[] bytes = IOUtils.toByteArray(fileIn, fileInfo.getStandardInformation().getAllocationSize());
      }
   }

Why read files into a byte array?

I am writing a protocol plugin for Apache Nutch. And the API expects file content to be provided as byte[].

Why not have IOUtils read the complete file?

The call IOUtils.toByteArray(fileIn) would read the complete file. But it fails with an IOException if the file is bigger than 2 GB. So I'd like to specify the maximum size to read. And here the IOUtils API allows to specify the amount of bytes using IOUtils.toByteArray(fileIn, amount). But the caveat is that now the call will fail if the file is smaller. Thus I need to know the filesize (and thus the amount of bytes I want to read) before making that call.


Solution

  • Looking at their github repo, the remoteCopyTo() function uses this:

    long fileSize = getFileInformation(FileStandardInformation.class).getEndOfFile();
    

    So, in your case, you want to try the following:

    long fileSize = fileInfo.getStandardInformation().getEndOfFile();
    

    I believe this will give you the actual size.