JDK-4831749 : channel open/close bug on windows
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.1_01
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2003-03-13
  • Updated: 2003-03-13
  • Resolved: 2003-03-13
Related Reports
Duplicate :  
Description

Name: eaC66865			Date: 03/12/2003


The code below runs properly on Solaris. It can also be
made to work on Windows by commenting out the indicated
lines of code. But with those lines in, the program fails
under windows 2000.

THE ERROR
---------
C:\test>"C:\j2sdk1.4.1_01\bin\java.exe" -ea -classpath
"P:\dev\lab\nio\build\classes\;P:\dev\util\build\classes" NioMappingBug
   read: |test data|
ch size: 9, buff capacity: 9, pos: 0, lim: 9

java.io.FileNotFoundException: testFile (Access is denied)
        at java.io.FileOutputStream.open(Native Method)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:176)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:131)
        at NioMappingBug.createOutputStream(NioMappingBug.java:84)
        at NioMappingBug.testTwoWrites(NioMappingBug.java:158)
        at NioMappingBug.run(NioMappingBug.java:41)
        at NioMappingBug.main(NioMappingBug.java:24)
Failure: The attempt to create an output stream failed
Exception in thread "main" java.lang.AssertionError
        at NioMappingBug.fail(NioMappingBug.java:179)
        at NioMappingBug.createOutputStream(NioMappingBug.java:88)
        at NioMappingBug.testTwoWrites(NioMappingBug.java:158)
        at NioMappingBug.run(NioMappingBug.java:41)
        at NioMappingBug.main(NioMappingBug.java:24)

THE CODE
--------
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

import java.util.*;

public class NioMappingBug {
  String testData = "test data";
  String moreData = "more data";

  File testFile = new File("testFile");

  Charset charset = Charset.forName("UTF-8");
  CharBuffer charBuffer;

  FileChannel testChannel;
  ByteBuffer byteBuffer;

  FileOutputStream outputStream;

  public static void main(String[] argv) {
    NioMappingBug app = new NioMappingBug();
    app.run();
  }

  public void run() {
    setup();
    String result = "";

//-----------------------------------------------------------
//INCLUDE THIS TO SEE THE BUG (Length = 18, but data = "test data")
//COMMENT IT OUT TO SEE THE PROGRAM SUCCEED
    if (testFile.exists()) deleteFile();
    writeFile();
//-----------------------------------------------------------

    result = readFile(testFile).toString();

    setup();
    testTwoWrites();
    result = readFile(testFile).toString();
//-----------------------------------------------------------
//BUG OCCURS HERE
    expectEquals(testData+moreData, result);
//-----------------------------------------------------------
  }

  public void setup() {
    charBuffer = CharBuffer.allocate(16);
    testChannel = null;
    byteBuffer = null;
    outputStream = null;
  }

  /**
   * Attempt to write to a file that doesn't exist.
   */
  public void writeFile() {
    createOutputStream();
    expect(testFile.exists()); // Creating an output stream also creates
the file
    testChannel = outputStream.getChannel();
    charBuffer.put(testData);    // position=9, limit=16
    charBuffer.flip();           // position=0, limit=9
    byteBuffer = charset.encode(charBuffer);
    try {
      output(byteBuffer, testChannel);
    }
    catch (IOException ioe) {
      ioe.printStackTrace();
      fail("Error writing the file.");
    }
    try {
      outputStream.close(); // closes the channel, as well
    }
    catch (IOException ioe) {
      ioe.printStackTrace();
      fail("Could not close the newly written file.");
    }
  }

  private void createOutputStream() {
    try {
      outputStream = new FileOutputStream(testFile);
    }
    catch (IOException ioe) {
      ioe.printStackTrace();
      fail("The attempt to create an output stream failed");
    }
  }

  /**
   * This is the <i>right</i> way to write.
   *
   */
  public void output(ByteBuffer byteBuffer, WritableByteChannel channel)
    throws IOException {
    int bytesWritten = 0;
    while (bytesWritten < byteBuffer.remaining()) {
      // Loop if only part of the buffer contents get written.
      bytesWritten = channel.write(byteBuffer);
      if (bytesWritten == 0) {
        // Media full? We could do some retries here, or throw an
exception
        throw new IOException("Unable to write to channel. Media may be
full.");
      }
    }
  }

  public CharBuffer readFile(File file) {
    CharBuffer resultBuffer = null;
    try {
      FileInputStream stream = new FileInputStream(file);
      FileChannel fileChannel = stream.getChannel();
      int max = Integer.MAX_VALUE;
      if (fileChannel.size() > max) {
        throw new IOException("File too large: " + file.getPath());
      }
      int size = (int) fileChannel.size();
      // Mapped read
      byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0,
size);
      //        // This code solves the problem
      //        byteBuffer = ByteBuffer.allocate(size);
      //        while (byteBuffer.hasRemaining()) {
      //          int bytesRead = fileChannel.read(byteBuffer); //
increments position
      //          if (bytesRead == 0) {
      //            throw new IOException("Read failure: " +
file.getPath());
      //          }
      //        }
      //        byteBuffer.flip();  // position -> 0, limit -> capacity
      resultBuffer = charset.decode(byteBuffer);
      stream.close();     //closes the associated channel as well
      byteBuffer = null;  // attempt to "unmap" the buffer
      report("   read: |" + resultBuffer.toString() + "|");
      report("ch size: " + size + ", buff capacity: " +
resultBuffer.capacity()
             +  ", pos: " + resultBuffer.position() + ", lim: " +
resultBuffer.limit()
             + "\n");
    }
    catch (IOException ioe) {
      ioe.printStackTrace();
      fail("readFile: Error reading file: " + testFile.getPath());
    }
    return resultBuffer;
  }

  public void report(String s) {
    System.out.println(s);
  }

  public void deleteFile() {
    boolean success = testFile.delete();
    if (!success) {
      fail("Delete failed: "+ testFile.getPath());
    }
    expect(!testFile.exists());
  }

  public void testTwoWrites() {
    createOutputStream();
    testChannel = outputStream.getChannel();
    charBuffer.put(testData);    // position=9, limit=16
    charBuffer.flip();           // position=0, limit=9
    try {
      byteBuffer = charset.encode(charBuffer);
      testChannel.write(byteBuffer);
      charBuffer.clear();
      charBuffer.put(moreData);
      charBuffer.flip();
      byteBuffer = charset.encode(charBuffer);
      testChannel.write(byteBuffer);           // do the 2nd write
      outputStream.close();  // closes the channel, as well
    }
    catch (IOException e) {
      fail("TwoWritesToNonAppendedFile: Error during I/O");
    }
  }

  public void fail(String msg) {
    System.out.println("Failure: "+msg);
    assert false; // sets up a linked stack trace in the CodeGuide IDE
    System.exit(0);
  }

  public void expect(boolean condition) {
    if (condition) return;
    System.out.println("Expected condition failed");
    assert false; // sets up a linked stack trace in the CodeGuide IDE
    System.exit(0);
  }

  public void expectEquals(String expected, String actual) {
    if (expected.equals(actual)) return;
    System.out.println("Comparison failed");
    showDiff(expected,actual);
    assert false; // sets up a linked stack trace in the CodeGuide IDE
    System.exit(0);
  }

  /**
   * Displays the expected and actual string values, like this:<pre>
   * expected: |....the expected string here....|
   *   actual: |....the actual string here....|
   * </pre>
   * (The vertical bars help to clarify things when NLs or whitespace
   * characters are present in the strings.)
   */
  protected void showDiff(String expected, String actual) {
    System.out.println("expected: |"+expected+"|");
    System.out.println("  actual: |"+actual+"|");
  }

}

======================================================================

Comments
WORK AROUND Name: eaC66865 Date: 03/12/2003 None I'm aware of. ======================================================================
11-06-2004