特集 J#の真実 Part 2
3.ライブラリの互換性(2)
株式会社ピーデー 川俣 晶
2001/11/16
|
|
一方、ファイル入出力時の文字コード変換を正しく処理するには、InputStreamReaderとOutputStreamWriterを自前で書けばよい。少し長いが、筆者の書いたものを以下に示す。なお、OutputStreamWriterは元々JDKではJISコードの変換に問題があったので、それに対処するコードになっており、今回はそれに書き足している。
1: import java.io.*;
2: import java.util.*;
3:
4: public class InputStreamReader extends Reader
5: {
6: private String enc;
7: private InputStream in;
8: private byte [] buf;
9: private int filled;
10: private int used;
11: private String stringBuffer;
12: private int stringPointer;
13: final private int bufferSize = 2048;
14: private boolean eatLF;
15: private void readNextBlock() throws IOException
16: {
17: if( in.available() == 0 )
18: {
19: filled = -1;
20: used = 0;
21: return;
22: }
23: buf = new byte[bufferSize];
24: filled = in.read(buf);
25: used = 0;
26: }
27: private int readNextByte() throws IOException
28: {
29: if( filled == -1 ) return -1; //
EOF
30: if( filled == used )
31: {
32: readNextBlock();
33: if( filled == -1 ) return -1;
// EOF
34: }
35: int r = (buf[used] & 0xff);
36: used ++;
37: return r;
38: }
39: private boolean isEOF()
40: {
41: return filled == -1;
42: }
43: // limited to use for ASCII compatible
encodings
44: private String readString() throws IOException
45: {
46: if( isEOF() ) return null;
47: byte [] ar = new byte [bufferSize];
48: int count = 0;
49: while( true ) {
50: if( count >= bufferSize ) break;
51: int r = readNextByte();
52: if( r == -1 ) break;
53: if( r == 0x0d )
54: {
55: ar[count] = (byte)r;
56: count ++;
57: eatLF = true;
58: break;
59: }
60: if( r == 0x0a )
61: {
62: ar[count] = (byte)r;
63: count ++;
64: if( eatLF )
65: {
66: eatLF =
false;
67: continue;
68: }
69: break;
70: }
71: ar[count] = (byte)r;
72: count ++;
73: eatLF = false;
74: }
75: DotNetString s = new DotNetString( ar, 0, count,
enc );
76: return s.toString();
77: }
78: public InputStreamReader( InputStream in, String enc ) throws
UnsupportedEncodingException
79: {
80: this.in = in;
81: this.enc = enc;
82: filled = 0;
83: used = 0;
84: eatLF = false;
85: // for detecting validity
of enc
86: DotNetString s = new DotNetString( ""
);
87: s.getBytes(enc);
88: }
89: public InputStreamReader( InputStream in )
90: {
91: this.in = in;
92: this.enc = "SJIS";
93: filled = 0;
94: used = 0;
95: eatLF = false;
96: }
97: public void close() throws IOException
98: {
99: in.close();
100: }
101: public String getEncoding()
102: {
103: return enc;
104: }
105: public int read() throws IOException
106: {
107: if( stringBuffer == null || stringPointer >= stringBuffer.length()
)
108: {
109: stringBuffer = readString();
110: if( stringBuffer == null ) return -1;
// EOF
111: if( stringBuffer.length() == 0 ) return
-1; // EOF
112: stringPointer = 0;
113: }
114: int ch = stringBuffer.charAt(stringPointer);
115: stringPointer++;
116: return ch;
117: }
118: public int read( char cbuf[], int off, int len ) throws IOException
119: {
120: int count = 0;
121: for( int i=0; i<len; i++ )
122: {
123: int r = read();
124: if( r == -1 )
125: {
126: break;
127: }
128: cbuf[i+off] = (char)r;
129: count++;
130: }
131: return count;
132: }
133: public boolean ready() throws IOException
134: {
135: return true;
136: }
137: } |
|
自前で作成したInputStreamReaderクラスのソースコード |
ファイルの入力時に文字コードの変換を正しく行う。 |
|
1: import java.net.*;
2: import java.io.*;
3: import java.util.*;
4:
5: class OutputStreamWriter extends Writer
6: {
7: private StringBuffer remainingString;
8: private String enc;
9: private OutputStream out;
10: //public String testString;
11: public OutputStreamWriter(OutputStream out) {
12: this.out = out;
13: this.enc = "8859_1";
14: remainingString = new StringBuffer();
15: }
16: public OutputStreamWriter(OutputStream out,
17:
String enc) throws UnsupportedEncodingException {
18: this.out = out;
19: this.enc = enc;
20: // for detecting validity
of enc
21: DotNetString s = new DotNetString( ""
);
22: s.getBytes(enc);
23: remainingString = new StringBuffer();
24: }
25: public void close() throws IOException {
26: flush();
27: out.close();
28: }
29: public void flush() throws IOException {
30: byte [] ar = new DotNetString( remainingString.toString()
).getBytes(enc);
31: out.write( ar, 0, ar.length );
32: out.flush();
33: remainingString = new StringBuffer();
34: }
35: public String getEncoding() {
36: return enc;
37: }
38: public void write(String str,
39: int
off,
40: int
len) throws IOException {
41: int p = off;
42: while( true ) {
43: if( p >= off+len ) break;
44: // calculate
next-line-top
45: boolean hasNextCR = true;
46: boolean hasNextLF = true;
47: int nextCR = str.indexOf(0x0d,p);
48: if( nextCR < 0 ) {
49: nextCR = off+len;
50: hasNextCR = false;
51: } else if( nextCR >= off+len )
{
52: nextCR = off+len;
53: hasNextCR = false;
54: } else {
55: nextCR++;
56: if( nextCR < off+len
&& str.charAt(nextCR) == 0x0a ) {
57: nextCR++;
58: }
59: }
60: int nextLF = str.indexOf(0x0a,p);
61: if( nextLF < 0 ) {
62: nextLF = off+len;
63: hasNextLF = false;
64: } else if( nextLF >= off+len )
{
65: nextLF = off+len;
66: hasNextLF = false;
67: } else {
68: nextLF++;
69: }
70: if( hasNextCR == false &&
hasNextLF == false ) break;
71: int next = Math.min( nextCR, nextLF
);
72: next = Math.min( next, off+len );
73: // convert
and write it
74: remainingString.append( str.substring(p,next)
);
75: byte [] ar = new DotNetString( remainingString.toString()
).getBytes(enc);
76: out.write( ar, 0, ar.length );
77: remainingString = new StringBuffer();
78: p = next;
79: }
80: remainingString.append( str.substring(p,off+len)
);
81: }
82: public void write(char cbuf[],
83: int
off,
84: int
len) throws IOException {
85: String s = new String( cbuf, off, len );
86: write( s, 0, s.length() );
87: }
88: public void write(int c) throws IOException {
89: char [] ar = new char[1];
90: ar[0] = (char)c;
91: write( ar, 0, 1 );
92: }
93: public static void main( String argv[] ) throws UnsupportedEncodingException,
IOException {
94: if( argv.length != 1 ) {
95: System.out.println("usage:
OutputStreamWriter FILENAME");
96: return;
97: }
98: BufferedReader br = new BufferedReader(
99: new InputStreamReader(
100: new FileInputStream( argv[0]
),
101: "SJIS"
102: )
103: );
104: StringBuffer sb = new StringBuffer();
105: while( true ) {
106: String s = br.readLine();
107: if( s == null ) break;
108: sb.append( s );
109: sb.append( "\015\012" );
110: }
111: ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
112: PrintWriter ps = new PrintWriter( new OutputStreamWriter(
baos1, "EUC" ) );
113: ps.print(sb.toString());
114: ps.close();
115: String r1 = baos1.toString("EUC");
116: System.out.println( "result1=" + r1.equals(
sb.toString() ) );
117:
118: BufferedReader br2 = new BufferedReader ( new StringReader(sb.toString()
) );
119: ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
120: PrintWriter ps2 = new PrintWriter( new OutputStreamWriter(
baos2, "EUC" ) );
121: while( true ) {
122: String s = br2.readLine();
123: if( s == null ) break;
124: ps2.println(s);
125: }
126: ps.close();
127: String r2 = baos2.toString("EUC");
128: System.out.println( "result2=" + r2.equals(
sb.toString() ) );
129: }
130: } |
|
自前で作成したOutputStreamWriterクラスのソースコード |
ファイルの出力時に文字コードの変換を正しく行う。JDKのJISコード変換には問題があり、もともとはそれに対処したコードであるが、それに文字コード変換の機能を追加している。 |
|
さて、これですべて終わりかと思いきや、ソケットの通信がうまくできない。例えば、単純なTCPのクライアントを記述しても、J#のクラスを呼ぶと接続できないという現象があり、これは.NET
FrameworkのTcpClientクラスなどを使うように書き換えてしまった。
Insider.NET 記事ランキング
本日
月間