Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[nio] Bug in FileChannel oder sitzt der Fehler vor dem Bildschirm?

2 views
Skip to first unread message

Michael Schierl

unread,
Mar 4, 2003, 5:43:21 PM3/4/03
to
Hi,

folgendes (Fast-)Minimalbeispiel:

import java.util.*;
import java.io.*;
import java.nio.channels.*;


public class ChannelBug {

public static final boolean USE_CHANNELS = true;

public static boolean copyFile(File src, File dst) {
try {
System.out.println("CopyFile: "+src+"-->"+dst);
FileInputStream fin=new FileInputStream(src);
FileOutputStream fout=new FileOutputStream(dst);
if (USE_CHANNELS) {
channelCopy(fin,fout);
} else {
streamCopy(fin,fout);
}
fout.flush();
fout.close();
fin.close();
dst.setLastModified(src.lastModified());
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}

public static void channelCopy(FileInputStream fin,
FileOutputStream fout)
throws IOException {
FileChannel cin=fin.getChannel(),
cout=fout.getChannel();
System.out.println(cin +"-->"+cout);
long cnt=cin.size();
while(cnt>0) {
long done=cin.transferTo(0,cnt,cout); // Zeile 40
cnt-=done;
}
cin.close();
cout.close();
}

public static void streamCopy(InputStream in, OutputStream out)
throws IOException {
byte[] bs = new byte[8192];
int length;
while ((length = in.read(bs)) != -1) {
out.write(bs,0,length);
}
}

public static void main(String[] args) {
copyFile
(new File("C:\\temp\\TWAIN.log"),
new File("N:\\temp\\2.log"));
}
}

Ich verwende hier Sun Java 1.4.1_01-b01 auf WinME - N: ist eine
Netzwerkfreigabe eines XP-Rechners.

Wenn ich obiges Programm laufen lasse, und einer der beiden Pfade auf
das Netzwerklaufwerk zeigt, gibt es 3 Möglichkeiten

a) es geht
b) java.io.IOException: Die angegebene Prozedur wurde nicht gefunden
at sun.nio.ch.FileChannelImpl.unmap0(Native Method)
at sun.nio.ch.FileChannelImpl.unmap(FileChannelImpl.java:696)
at
sun.nio.ch.FileChannelImpl.transferToTrustedChannel(FileChannelImpl.java:426)
at
sun.nio.ch.FileChannelImpl.transferTo(FileChannelImpl.java:490)
at StreamBug.channelCopy(StreamBug.java:40)
at StreamBug.copyFile(StreamBug.java:17)
at StreamBug.main(StreamBug.java:57)

c) java.io.IOException: Bad file descriptor
at sun.nio.ch.FileChannelImpl.unmap0(Native Method)
at sun.nio.ch.FileChannelImpl.unmap(FileChannelImpl.java:696)
[...]

Welche Möglichkeit eintrifft, ist bei ein- und derselben Datei immer
gleich, aber ich hab keine Gesetzmäßigkeiten gefunden, welche Datei
wie "reagiert".

Wenn ich allerdings beide Dateien auf C: habe, oder wenn ich
USE_CHANNELS auf false setze (also obige streamCopy-Funktion läuft),
funktioniert der Code wie gewünscht.

Ist das ein Fehler in meinem Programm oder ein Bug in NIO?

TIA,

Michael
--
"New" PGP Key! User ID: Michael Schierl <schi...@gmx.de>
Key ID: 0x58B48CDD Size: 2048 Created: 26.03.2002
Fingerprint: 68CE B807 E315 D14B 7461 5539 C90F 7CC8
http://home.arcor.de/mschierlm/mschierlm.asc

Bernd Eckenfels

unread,
Mar 5, 2003, 1:11:04 AM3/5/03
to
Michael Schierl <schierl...@gmx.de> wrote:
> folgendes (Fast-)Minimalbeispiel:

nicht deine frage aber:

> fout.flush();
> fout.close();

ist meiner Meinung nach doppelt gemoppelt.

> public static void channelCopy(FileInputStream fin,
> FileOutputStream fout)

nur der Reinheit der Lehre wegen:

public static void channelCopy(InputStream fin,
OutputStream fout)

> long cnt=cin.size();
> while(cnt>0) {
> long done=cin.transferTo(0,cnt,cout); // Zeile 40
> cnt-=done;
> }

bist du sicher, dass du das .size() nicht innerhalb der While Schleifen
haben willst um auch streams zu unterstuetzen?

> cin.close();
> cout.close();

wenn du spaeter die streams schliesst, muss man hier auch die channels
schliessen?

> while ((length = in.read(bs)) != -1) {
> out.write(bs,0,length);
> }

das is auch nicht stream safe.

Gruss
Bernd
--
eckes privat - http://www.eckes.org/
Project Freefire - http://www.freefire.org/

Michael Schierl

unread,
Mar 5, 2003, 4:29:12 PM3/5/03
to
Bernd Eckenfels <ec...@calista.eckenfels.6bone.ka-ip.net> wrote:

>Michael Schierl <schierl...@gmx.de> wrote:
>> folgendes (Fast-)Minimalbeispiel:
>
>nicht deine frage aber:
>
>> fout.flush();
>> fout.close();
>
>ist meiner Meinung nach doppelt gemoppelt.

War da nicht mal ein Bug in einer Java-Version, die beim close() das
flush() vergessen hat? Gut, das war BufferedOutputStream, und den hab
ich hier nicht. Aber da flush() vor close() nicht schadet...

>> public static void channelCopy(FileInputStream fin,
>> FileOutputStream fout)
>
>nur der Reinheit der Lehre wegen:
>
> public static void channelCopy(InputStream fin,
> OutputStream fout)

Input- und OutputStream haben aber (zumindest bei mir) kein
getChannel. Und bevor ich dann wieder nach FileXXXputStream caste und
eine ClassCastException riskiere...

>bist du sicher, dass du das .size() nicht innerhalb der While Schleifen
>haben willst um auch streams zu unterstuetzen?

Ja. Ich will das ganze so performant wie es in Java möglich ist,
haben. Wenn du was performanteres als Channels weißt, nur her damit.


>> cin.close();
>> cout.close();
>
>wenn du spaeter die streams schliesst, muss man hier auch die channels
>schliessen?

Schadet es, wenn ich beide zumache?


>> while ((length = in.read(bs)) != -1) {
>> out.write(bs,0,length);
>> }
>
>das is auch nicht stream safe.

Echt? Wie geht es "stream safe" (was das auch immer sein mag)?
Da in.read() blockt, wenn nichts da ist, sollte das IMHO mit allen
Streams fertig werden. CMIIW.

Michael

PS: War noch ein Bug drin, es hätte

| long cnt=cin.size(), pos=0;
| while(pos<cnt) {
| long done=cin.transferTo(pos,cnt-pos,cout);
| pos+=done;
| }

heißen müssen, weil transferTo immer bezüglich dem Dateianfang
rechnet, nicht bezüglich der letzten Stelle.

Bernd Eckenfels

unread,
Mar 5, 2003, 8:30:29 PM3/5/03
to
Michael Schierl <schierl...@gmx.de> wrote:
>>nur der Reinheit der Lehre wegen:
>>
>> public static void channelCopy(InputStream fin,
>> OutputStream fout)
>
> Input- und OutputStream haben aber (zumindest bei mir) kein
> getChannel. Und bevor ich dann wieder nach FileXXXputStream caste und
> eine ClassCastException riskiere...

Ja richtig, ich habs gemerkt und vergessen den absatz zu loeschen :)


Haste mal bemessen wieviel schneller die Streams sind?

Gruss
Bernd
yy

Michael Schierl

unread,
Mar 8, 2003, 3:17:29 PM3/8/03
to
Bernd Eckenfels <ec...@calista.eckenfels.6bone.ka-ip.net> wrote:

>Haste mal bemessen wieviel schneller die Streams sind?

Du meinst die Channels, oder?

42 MB, kopiert von einem Laufwerk auf dasselbe:

Streams: 34 Sekunden
Channels: 17 Sekunden.

Also ziemlich genau die Hälfte der Zeit. Und die Dateien, die mit
beiden Verfahren erzeugt werden, sind (zum Glück) beide identisch.

Bei Dateien größer als 100MB scheinen die Channels auf WinME
allerdings zu spontanem Bluescreening/zu Aufhängern zu neigen :-(

Michael, sich jetzt jdk141_02 ziehend

0 new messages