プログラマ38の日記

主にプログラムメモです。

Salesforce: Shift_JISのテキストファイルを作成して添付ファイルに登録する

SalesforceのApexプログラムの中で、Shift_JISCSVファイルを作成したい時があります。

 

Salesforceの文字列とバイナリは、StringとBlobを使います。BlobからStringとその逆の変換の関数は用意されていますが、その際のエンコーディングUTF-8となります。

 

そこで、エンコーディングをShiftJISにするために工夫が必要になりますが、次の2点のやり方を考えました。

 

  1. CSV出力するVisualforceを作成し、PageReference.getContent()を使う
  2. EncodingUtil.urlEncodeとEncodingUtil.convertFromHexを利用し、Shift_JISのバイナリに変換する

 

1の方法はシンプルですが、PageReference.getContent()が利用できない(トリガでは@futureが必要となる)箇所があります。
やり方は、CSV出力用のVisualforceを作成し、

<!-- CSVPage という名前のページ -->
<apex:page controller="SampleController" contentType="text/csv;charset=Windows-31J;#test.csv">{!csvtext}</apex:page>

 コントローラ側でPageReference.getContent()を使いバイナリを取得します。

PageReference csvpage = Page.CSVPage;
Blob csvcontent = csvpage.getContent();

ポイントは、Visualforceページで文字コードを指定できるので、そこでShift_JISを指定します。

 

2の方法は少々強引ですが、次のようなコードでバイナリを作成することができます。下記のstrToShiftJISBlob関数に、引数にファイルにしたい文字列を指定してバイナリに変換します。
もちろん処理のコストは高く、長い文字列は扱えませんが、短い文字なら問題ありません。

    public static Blob strToShiftJISBlob (String str){

        String body = '';

        for( Integer i = 0 ; i < str.length(); i++ ){
            String moji = str.substring(i,i+1);

            String encoded = EncodingUtil.urlEncode(moji , 'Windows-31J' );

            if(encoded.length() == 1){
                Integer charval = moji.getChars()[0];
                encoded = '%' + toHex(charval );
            }

            body += encoded;
        }


        body = body.replaceAll('%','');

        Blob blobValue = EncodingUtil.convertFromHex(body);

        return blobValue ;
    }

    private static Map<Integer,String> hexmap = new Map<Integer,String>{
        0  => '0'
       ,1  => '1'
       ,2  => '2'
       ,3  => '3'
       ,4  => '4'
       ,5  => '5'
       ,6  => '6'
       ,7  => '7'
       ,8  => '8'
       ,9  => '9'
       ,10 => 'A'
       ,11 => 'B'
       ,12 => 'C'
       ,13 => 'D'
       ,14 => 'E'
       ,15 => 'F'
    };


    private static String toHex( Integer val ){

    //処理場ありえないが、変換できないものは?
        if(val > 255 ){
            val = '?'.getChars()[0]; 
        }

        Integer moji1 = val / 16;
        Integer moji2 = Math.mod(val , 16);


        return hexmap.get(moji1 ) + hexmap.get(moji2 );
    }

 

最後に

データローダを使わずにSalesforceだけで簡潔させようとすると、エンコーディングUTF-8が標準となるので、ShiftJISにしようとするとコードが増えるなーと感じました。

あと、ShiftJIS、ShiftJISと書いていますが、コード上はWindows-31J(CP932)にしています。エンコーディングってややこしいですね。。