1

I read a file from the database that is in a byte[] array, using the ByteArrayInputStream.

InputStream input = new ByteArrayInputStream(lc.getTable());

For a further processing of the file I need a FileInputStream. But I don't want to save the file on the hard disk first to read it again.

Can this be done or does the file have to be written out first?

John
  • 795
  • 3
  • 15
  • 38
  • 3
    What do you think a `FileInputStream` does... It has `File` in there for a purpose. If you don't want files to disk, then don't use a `FileInputStream` (also you probably need an `OutputStream` not an `InputStream`. – M. Deinum Nov 20 '19 at 09:34
  • Why does the further processing need a `FileInputStream` specifically? FileInputStreams are used for handling files. If this further processing code would also work on something that isn't a file it should just accept an `InputStream`, which your `ByteArrayInputStream` is already suitable for. – Nyubis Nov 20 '19 at 09:35
  • `FileInputStream` constructor checks if the file on the given path exists and can be read, so the short answer would be no. – Petar Mitrovic Nov 20 '19 at 09:38
  • You already have an `InputStream` in the `ByteArrayInputStream`. If something downstream specifically requires a `FileInputStream` (a) you are hosed and (b) it should be redesigned to use `InputStream`. – user207421 Nov 20 '19 at 09:40
  • You could create a temp file, that way it won't persist on disc. Other than that you can't have a FileStream without a File... – T A Nov 20 '19 at 09:42

1 Answers1

2

Not really. Then the further processing is overspecified; it should only require an InputStream. One could create a temporary deleted-on-exit file using the Files class. One could create an input output pipe involving an extra thread and still a physical file. One could use a File on a RAM disk.

However we can create our own FileInputStream, that redirects/delegates to your ByteArrayInputStream:

public class FakeFileInputStream extends FileInputStream {
    private final InputStream sourceInput;

    //public FakeFileInputStream(String name, InputStream sourceInput)
    //        throws FileNotFoundException {
    //    super(name);
    //    this.sourceInput = sourceInput;
    //}

    // @Torben offered this solution, which does not need an existing file.
    public FakeFileInputStream(InputStream sourceInput) {
        super(new FileDescriptor());
        this.sourceInput = sourceInput;
    }


    @Override
    public int read() throws IOException {
        return sourceInput.read();
    }

    @Override
    public int read(byte[] b) throws IOException {
        return sourceInput.read(b);
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return sourceInput.read(b, off, len);
    }

    @Override
    public long skip(long n) throws IOException {
        return sourceInput.skip(n);
    }

    @Override
    public int available() throws IOException {
        return sourceInput.available();
    }

    @Override
    public void close() throws IOException {
        sourceInput.close();
        //super.close();
    }

    @Override
    public FileChannel getChannel() {
        throw new UnsupportedOperationException();
    }

    @Override
    public synchronized void mark(int readlimit) {
        sourceInput.mark(readlimit);
    }

    @Override
    public synchronized void reset() throws IOException {
        sourceInput.reset();
    }

    @Override
    public boolean markSupported() {
        return sourceInput.markSupported();
    }
}

Old Note: the out-commented constructor would open the passed file name, and at the end close it, but do nothing with it. You could pass any existing file.

Note: thanks to @Torben for a version using an empty FileDescriptor.

(To create such a wrapper/delegating class: if the IDE offers no generation of a delegating class, simply override all methods, and replace "super." with "delegate.".)

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • 1
    This will throw a FileNotFoundException because FileInputStream requires a name of an existing file. You can pass a `new FileDescriptor()` to it, though. – Torben Nov 20 '19 at 09:47
  • @Torben Thanks very much, indeed one needs an existing file, which will be opened. Though no reading needs to happen. – Joop Eggen Nov 20 '19 at 09:54
  • 1
    Perhaps, the very reason why the subsequent processing requires a `FileInputStream` is the need to invoke `getChannel()` or `getFD()` on it... – Holger Nov 26 '19 at 14:19
  • @Holger _yes, there is always that,_ hence my `getChannel` throws an UnsupportedOperationException. By no means this is a bullet proof solution. – Joop Eggen Nov 26 '19 at 14:28