HELP: java1.4.2 on windows, FileChannel.Close

Discussion in 'Java' started by Andrew Rollings, Jan 31, 2004.

  1. Hi...
    I'm having a few problems with the close method of the FileChannel class in
    Sun java 1.4.2 (latest as of this date) on Windows.
    The code I've written seems to perform as expected on both MacOsX and linux,
    so I'm wondering if anyone has come across similar circumstances, and has
    found a workaround.

    Or alternatively, just tell me what I'm doing that's dumb.

    I have a class that maintains a TreeMap of FileChannels. At a certain point
    in the class execution, I iterate through the map, and close out all of the
    channels, and then attempt to delete the underlying file.
    The code to this this is as follows:


    -- begin excerpt
    Iterator iter = m_FileChannelMap.keySet().iterator();
    java.util.Vector keysToRemove = new java.util.Vector();
    while ( iter.hasNext() )
    {
    Long lKey = ( Long ) iter.next();
    if (lKey.longValue() < 0)
    {
    // get the channel and close it
    FileChannel fc = (FileChannel)m_FileChannelMap.get(lKey);
    fc.truncate(0);
    fc.force(true);
    fc.close();

    // okay - file channel should be closed... we can delete the
    // file it represents...
    String strFilename = m_strFileroot +
    this.getSegmentName(lKey.longValue());
    if (!strFilename.endsWith(".T")) throw new IOException("Invalid
    segment");
    java.io.File fSegment = new File(strFilename);
    if (false == fSegment.delete())
    {
    throw new IOException("Cannot close .T segment:" +
    strFilename );
    }
    }
    }
    -- end excerpt

    The problem is, that the IOException is *always* thrown. It seems that
    FileChannel.close() does not immediately close the channel. I'm wondering if
    this is anything to do with the fact that I'm maintaining a reference to the
    FileChannel object in the TreeMap, but I don't see why that should be the
    case. Anyway, this code works perfectly on Mac and Linux, but appears to
    barf out on Windows.

    Can anyone tell me what's wrong with the code? Failing that can anyone
    suggest an alternate method that will work?
    (And as an aside, is it safe to remove an item from the map while I'm
    iterating through it? I don't currently do that, but I may want to at some
    point.)

    Thanks for reading.

    Andrew
     
    Andrew Rollings, Jan 31, 2004
    #1
    1. Advertising

  2. Andrew Rollings wrote:

    > Hi...
    > I'm having a few problems with the close method of the FileChannel class in
    > Sun java 1.4.2 (latest as of this date) on Windows.
    > The code I've written seems to perform as expected on both MacOsX and linux,
    > so I'm wondering if anyone has come across similar circumstances, and has
    > found a workaround.
    >
    > Or alternatively, just tell me what I'm doing that's dumb.
    >
    > I have a class that maintains a TreeMap of FileChannels. At a certain point


    That's dumb unless it's important that the channels remain always in
    order by whatever key you use, including if you need to use the methods
    specific to the SortedSet interface. In any other circumstance a
    HashMap is a better choice. That isn't relevant to your problem, however.

    > in the class execution, I iterate through the map, and close out all of the
    > channels, and then attempt to delete the underlying file.
    > The code to this this is as follows:
    >
    >
    > -- begin excerpt
    > Iterator iter = m_FileChannelMap.keySet().iterator();


    I'd iterate over the entry set, myself, since you are going to retrive
    the value for each key anyway. That's not causing your problem either
    though.

    > java.util.Vector keysToRemove = new java.util.Vector();


    You don't appear to use this Vector.

    > while ( iter.hasNext() )
    > {
    > Long lKey = ( Long ) iter.next();
    > if (lKey.longValue() < 0)
    > {


    That's a bit odd. You identify the entries to close by their keys? I
    thought you were closing them all. Did you somehow arrange that the
    keys you were interested in would all be negative, or did you rekey the
    channels? (The latter would be quite inefficient, and more so for a
    TreeMap than for a HashMap.)

    > // get the channel and close it
    > FileChannel fc = (FileChannel)m_FileChannelMap.get(lKey);
    > fc.truncate(0);
    > fc.force(true);
    > fc.close();
    >
    > // okay - file channel should be closed... we can delete the
    > // file it represents...
    > String strFilename = m_strFileroot +
    > this.getSegmentName(lKey.longValue());
    > if (!strFilename.endsWith(".T")) throw new IOException("Invalid
    > segment");
    > java.io.File fSegment = new File(strFilename);
    > if (false == fSegment.delete())
    > {
    > throw new IOException("Cannot close .T segment:" +
    > strFilename );
    > }
    > }
    > }
    > -- end excerpt
    >
    > The problem is, that the IOException is *always* thrown. It seems that
    > FileChannel.close() does not immediately close the channel.


    From the API docs of FileChannel's superclass,
    AbstractInterruptibleChannel: "This class encapsulates the low-level
    machinery required to implement the asynchronous closing and
    interruption of channels." It would appear, then, that asynchronous
    closing is a design feature of the class.

    > I'm wondering if
    > this is anything to do with the fact that I'm maintaining a reference to the
    > FileChannel object in the TreeMap, but I don't see why that should be the
    > case.


    No, there is no reason why holding a reference in any particular place
    would affect the behavior of an object in any way. Affect the behavior
    of the GC, yes, but not of the object.

    > Anyway, this code works perfectly on Mac and Linux, but appears to
    > barf out on Windows.


    I'd say that the code is just plain buggy, even if so far the problem
    has only manifested on Windows. Since you are already truncating the
    files to zero length, perhaps it would be sufficient to flag them for
    deletion on JVM exit instead of deleting them immediately (via
    File.deleteOnExit()). If you must affirmatively delete them then you
    must be prepared to handle the possibility that they are sill open when
    you attempt to do so. One way of handling that would be to catch the
    exception and try again after a delay.

    > Can anyone tell me what's wrong with the code? Failing that can anyone
    > suggest an alternate method that will work?


    See above.

    > (And as an aside, is it safe to remove an item from the map while I'm
    > iterating through it? I don't currently do that, but I may want to at some
    > point.)


    Only if you do so via the iterator itself; otherwise (for TreeMap) you
    will get ConcurrentModificationException from you iterator after the
    removal. For Generic Maps behavior of the iterator subsequent to
    modification of the underlying Map is undefined. (See API docs for
    Map.keySet(), Map.entrySet(), and Map.values().)


    John Bollinger
     
    John C. Bollinger, Feb 2, 2004
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Spendius
    Replies:
    4
    Views:
    2,312
    Harald Hein
    Jul 4, 2003
  2. Roedy Green
    Replies:
    3
    Views:
    3,257
    Roedy Green
    Aug 14, 2003
  3. ruds
    Replies:
    0
    Views:
    375
  4. Iñaki Baz Castillo
    Replies:
    7
    Views:
    874
    Iñaki Baz Castillo
    Jan 12, 2010
  5. musart
    Replies:
    12
    Views:
    840
    jorge
    Apr 5, 2013
Loading...

Share This Page