S3にあるShift-JISのCSVファイルをLambda(node.js)で読み込んでUTF-8に変換してS3にアップする – AWS SDK for JavaScript v3

S3にあるShift-JISのCSVファイルをLambda(node.js)で読み込んでUTF-8に変換してS3にアップする – AWS SDK for JavaScript v3

Shift-JISのCSVファイルを用意します。機種依存文字とかも入れてみます。(①)

S3にあるShift-JISのCSVファイルをLambda(node.js)で読み込んでUTF-8に変換してS3にアップする - AWS SDK for JavaScript v3

streamのままuploadしたいので@aws-sdk/lib-storageをインストールします。文字コード関連はiconv-liteを使用します。

npm i --save @aws-sdk/client-s3 @aws-sdk/lib-storage iconv-lite

バケットのtmp/in.csvとしてcpしておきます。

Lambda(node.js)

Shift-JIS(機種依存文字が入っているのでCP932)のCSVファイルをS3に配置しているので、iconv-liteモジュールを使用してCP932で読み込む必要があります。

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { Upload } from '@aws-sdk/lib-storage'
import iconv from 'iconv-lite'

export async function handler(event, context) {
  const input = {
    Bucket: '<バケット名>',
    Key: 'tmp/in.csv'
  }
  const client = new S3Client({
    region: 'ap-northeast-1'
  })
  const command = new GetObjectCommand(input)
  const data = await client.send(command)
  // cp932(ms932)で読み込む
  const bodyContents = data.Body.pipe(iconv.decodeStream('CP932'))
  const upload = new Upload({
    client: client,
    params: {
      Bucket: '<バケット名>',
      Key: 'var/data/out.csv',
      Body: bodyContents // stream upload
    }
  })
  upload.on('httpUploadProgress', progress => {
    console.log(progress)
  })
  await upload.done()
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!')
  }
  return response
}

これでバケットのvar/data/out.csvにPUTしなおしています。

PUTしなおしたファイルは文字コードがUTF-8に変わっています。

2次元配列に変換する

Shift-JISだとs3 selectできないので、そのまま取得し2次元配列に変換してみます。

GetObjectCommandとcsv-parse/syncモジュールを使用します。

$ npm i csv-parse

index.mjs

import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3' 
import { parse } from 'csv-parse/sync'
import iconv from 'iconv-lite'

export const handler = async(event) => {
  const input = {
    Bucket: '<バケット名>',
    Key: 'tmp/in.csv'
  }
  const client = new S3Client({
    region: 'ap-northeast-1'
  })
  const command = new GetObjectCommand(input)
  const data = await client.send(command)
  const bodyContents = data.Body.pipe(iconv.decodeStream('CP932'))
  const csv = parse(await streamToString(bodyContents),{
    columns: false, // JSON配列として扱いたい場合はtrue
    from_line: 2 // ヘッダ行スキップする(基底=1)
  })
  console.log(csv) // 2次元配列として扱える
  const response = {
    statusCode: 200,
     body: JSON.stringify('Hello from Lambda!'),
  }
  return response
}

async function streamToString(stream) {
  let chunks = []
  await new Promise((resolve, reject) => {
    stream.on('data', chunk => chunks.push(chunk))
    stream.on('error', reject)
    stream.on('end', () => resolve())
  })
  return chunks.join('')
}

ストリームを文字列変換してparseすればcsvを2次元配列として取得することができます。

parseのオプションによってJSON配列にすることも可能です。

参考サイト

iconv-lite
Convert character encodings in pure javascript.. Latest version: 0.6.3, last published: 2 years ago. Start using iconv-l...
@aws-sdk/lib-storage | AWS SDK for JavaScript v3
Documentation for AWS SDK for JavaScript v3
How to upload a stream to S3 with AWS SDK v3
I have to transfer a file from and API endpoint to two different bucket. The original upload is made using: curl -X PUT ...
文字コードがShift-JISのCSVファイルを読み込む方法@React [サンプル付き]
React や node.js は文字コードが utf-8 で動いているため、 utf-8 以外の CSVファ…

コメント

タイトルとURLをコピーしました