This discussion is archived
11 Replies Latest reply: Oct 10, 2007 3:02 AM by 807592 RSS

How to reopen FileInputStream?

807587 Newbie
Currently Being Moderated
Hello,

Is it possible to re-open a FileInputStream or somehow reset it to the beginning so that I can read from it again? I would like to be able to do this without knowing which file name that string represents. I have gotten the file descriptor and tried to create a new stream based on that, but I get a "bad file descriptor" exception. Does anyone know any other way to do this?

Thank you.


  • 1. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    Read the API docs for FileInputStream.getChannel().
  • 2. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    I have already tried that and I cannot get it to work. If I try to reset the channel to position 0, I get an exception:

    java.io.IOException: Bad file descriptor
         at sun.nio.ch.FileChannelImpl.position0(Native Method)
         at sun.nio.ch.FileChannelImpl.position(FileChannelImpl.java:284)

    If I try to get the descriptor from the existing stream and create a new stream based on that, I still get the same exception.

    FileInputStream does not support the reset() method.

    The issue may be due to the fact that the file is changed on disk, which is why I have to re-read it. However, the interface that I need to conform to only passes in the FileInputStream and not the File or its name. So how can I re-read the file that is associated with that stream without knowing its path?

    Does anyone have any other suggestions?
  • 3. Re: How to reopen FileInputStream?
    DrClap Expert
    Currently Being Moderated
    If you only have an InputStream defined as a parameter, and you need to read it twice, then your design is wrong. There is no guarantee that an InputStream can be reset, as you have already found out. It looks to me like the code you are writing isn't consistent with the interface you are attempting to implement.
  • 4. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    The design of the code assumed that the file represented by the stream was static over time so it would cache the contents of the file in its own implementation, which is a limitation of that implementation since it is not true for the scenario I am working with. Therefore, I need to provide my own implementation which would allow me to refresh the cache periodically and still work with other code written arround the interface presented by the original implementation. The problem is that the origial design did not account for the sort of situation I am dealing with.

    Since the stream can be constructed from a File, I was hoping there was some way to retrieve that File or its path from an existing stream to create a new one or to clone or reset the existing stream.



  • 5. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    With channels it is possible to re-read a FileInputStream.
    Here is a sample testing class (ReRead.java) to demonstrate it
    The way to use it is:
    1- Create a little testting text file (for instance sometextfile.txt).
    2- Execute the class from the console:
    java ReRead sometextfile.txt
    3- While the execution is waiting for keyboard input, modify sometextfile.txt.
    4- Hit <Enter> and look at the console.
    import java.io.*;
    import java.nio.*;
    import java.nio.channels.*;
        
    public class ReRead {
        public static void main(String[] args) throws Exception {
            if (args.length != 1)
                throw new Exception("\nUsage: java ReRead {text file name}");
            
            String fileName = args[0];
            FileInputStream fis = new FileInputStream(fileName); // The only FileInputStream used.
            
            // First time the FileInputStream is read.
            System.out.println("First read:");
            readFile(fis); // First time.
            
            System.out.print("Modify the '" + fileName + "' file and then hit <Enter> at the console.");
            System.in.read();
            
            // Second time the same FileInputStream is read.
            System.out.println("Second read:");
            readFile(fis);
            
            fis.close();
        }
        
        private static void readFile(FileInputStream fis) throws Exception {
            FileChannel fc = fis.getChannel();
            ByteBuffer bb = ByteBuffer.allocate(1024);
            WritableByteChannel wbc = Channels.newChannel(System.out);
            
            fc.position(0); // <-- IMPORTANT! this reset the channel position.
            System.out.println("-----start file-----");
            while (fc.read(bb) != -1) {
                bb.flip();
                wbc.write(bb);
                bb.clear();
            }
            System.out.println("-----end file-----");
        }
    }
  • 6. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    Thanks jfbriere. That is a good suggestion. Unfortunately, it did not solve my problem. The trouble is that the stream gets closed somewhere so even resetting the channel will not alow me to read from it. I get a java.nio.channels.ClosedChannelException. What I really need is a way to reopen a stream or channel.
  • 7. Re: How to reopen FileInputStream?
    DrClap Expert
    Currently Being Moderated
    I need to provide my own implementation which would allow me to refresh the cache periodically
    In that case I don't think I would attempt to have the method try to do the refreshing, since it clearly wasn't designed to do that. Instead I would try to have some outside object call the method repeatedly with the current data (at regular intervals, or whenever the resource changes, or at somebody's request).
  • 8. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    Yes, I understand what you are saying. However, the code that I am trying to work with is a provided by sun and it is used in third party code which I do not have control over. I can provide my own implementation of the interface defined by sun and then have the third party code use that implementation of the interface (it is possible to select the implementation through setting system properties) but I cannot add a wrapper around that object since the thrid party code will not use it.

    I guess it is just not possible to fix the problem. It is very frustrating that you need to pass a File or path to the constructor of a FileInputStream but there is no accessor which will give you that information back at a later time.


  • 9. Re: How to reopen FileInputStream?
    807587 Newbie
    Currently Being Moderated
    is you question actual?
    you can implement interface similar to javax.mail.internet.SharedInputStream and use it follow:

    SharedInputStream root = new SharedFileInputStream(fileName);
    InputStream is1 = root.newStream(0,-1);

    SomeClass.someMethod(is1);
    is1.close();


    InputStream is2 = root.newStream(0,-1);
    ...
    is2.close();

    if you encounter a difficulty with implementing SharedInputStream interface, i will post some working code here
  • 10. Re: How to reopen FileInputStream?
    807592 Newbie
    Currently Being Moderated
    Thank God for RandomAccessFile:
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    
    public class ResettableFileInputStream extends InputStream {
    
         RandomAccessFile raFile;
    
         long mark;
    
         public ResettableFileInputStream(File file) throws IOException {
              this.raFile = new RandomAccessFile(file, "r");
         }
    
         @Override
         public int read() throws IOException {
              return raFile.read();
         }
    
         @Override
         public synchronized void mark(int readlimit) {
              try {
                   mark = raFile.getFilePointer();
              } catch (Exception e) {
                   throw new RuntimeException(e);
              }
         }
    
         @Override
         public boolean markSupported() {
              return true;
         }
    
         @Override
         public int read(byte[] b, int off, int len) throws IOException {
              // TODO Auto-generated method stub
              return raFile.read(b, off, len);
         }
    
         @Override
         public synchronized void reset() throws IOException {
              raFile.seek(this.mark);
         }
    
         @Override
         public int available() throws IOException {
              // TODO Auto-generated method stub
              return (int) (raFile.length() - raFile.getFilePointer());
         }
    
         @Override
         public void close() throws IOException {
              // TODO Auto-generated method stub
              raFile.close();
         }
    
         @Override
         public long skip(long n) throws IOException {
              // TODO Auto-generated method stub
              long s = raFile.getFilePointer() + n;
              if (raFile.getFilePointer() + n > raFile.length())
                   n = raFile.length() - raFile.getFilePointer();
              raFile.seek(raFile.getFilePointer() + n);
              return n;
         }
    }
  • 11. Re: How to reopen FileInputStream?
    807592 Newbie
    Currently Being Moderated
    I am also facing the same issue. Not able to reset the FileInputStream. In the approach mentioned above (using RandomAccessFile), the same problem would occur right ? i.e If the input stream gets closed then you will get an exception, which is also the case while using FileIOChannel.

    Is there any other way of reseting the inputstream ?