特集 J#の真実 Part 2

3.ライブラリの互換性(2)

株式会社ピーデー 川俣 晶
2001/11/16

Page1 Page2 Page3 Page4 Page5

 一方、ファイル入出力時の文字コード変換を正しく処理するには、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クラスなどを使うように書き換えてしまった。


 INDEX
  [特集]J#の真実
  Part 2 JavaからJ#へ:プログラム移植の実際
    1.Visual J++ 6.0からの移行とコンパイラの互換性
    2.ライブラリの互換性(1)
  3.ライブラリの互換性(2)
    4.Javaと他言語のインターフェイス
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間