質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

コピー

元のオブジェクトを破壊することなく、オブジェクトの複製を生成することをコピーと呼びます。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

3590閲覧

Node.jsでfsを使ったファイルコピーができない

fuji_0055

総合スコア163

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

コピー

元のオブジェクトを破壊することなく、オブジェクトの複製を生成することをコピーと呼びます。

ファイルI/O

ファイルI/Oは、コンピューターにおけるファイルの入出力です。これは生成/削除やファイルを読み込んだり、出力をファイルに書き込むようなディレクトリやファイルの運用を含みます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/05/19 09:23

編集2020/05/19 09:35

#質問
Node.jsのfsで、fallocateコマンドで作った2.5Gバイトのファイルをコピーしようとしました。

bash

1fallocate -l 2.5G ~/test.txt

ファイルをコピーするシンプルなスクリプト「test.js」はtest.txtと一緒にホームディレクトリにあり、これはtest.txtをそのままtest2.txtとしてコピーするスクリプトです。

node

1const fs = require('fs'); 2 3fs.copyFileSync('test.txt', 'test2.txt');

これを以下のように実行しました。

bash

1node test.js

すると500MBくらいコピーしたところでこのようなエラーが発生してしまいます。

Error

1internal/errors.js:251 2 const [ code, uvmsg ] = errmap.get(ctx.errno); 3 ^ 4 5TypeError: errmap.get is not a function or its return value is not iterable 6 at Object.uvException (internal/errors.js:251:34) 7 at handleErrorFromBinding (fs.js:112:24) 8 at Object.copyFileSync (fs.js:1728:3) 9 at Object.<anonymous> (/home/pi/test.js:6:4) 10 at Module._compile (internal/modules/cjs/loader.js:778:30) 11 at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10) 12 at Module.load (internal/modules/cjs/loader.js:653:32) 13 at tryModuleLoad (internal/modules/cjs/loader.js:593:12) 14 at Function.Module._load (internal/modules/cjs/loader.js:585:3) 15 at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

先程のスクリプトまたはNode.jsの設定等のどこに問題があるのでしょうか。
#バージョン
Node: v10.20.1
Npm: 6.14.4
OS: Raspberry Pi 3 B+ Ubuntu 18.04(MATE)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

**Raspberry Pi 3 B+**ですと搭載メモリ(1GB)の関係で、メモリリークが発生しているのだと思います。

max_old_space_size オプションをつけて起動するというを試してみてはいかがでしょうか。

「NodeJS メモリ上限」(2語)や「NodeJS メモリ上限 オプション」(3語)で検索するとヒントが得られるかもしれません。


追記)
NodeJS のソースコードまで確認できていませんが、fs.copyFileSync() は、扱うファイルサイズに応じたメモリ領域を要するのかもしれません。

Stream レベルでのコピーも試してみてください。
時間はかかるかもしれませんが、限られたメモリサイズを用いてコピーするはずです。

javascript

1var fs = require("fs"); 2 3// 1. .pipe() で chunk データを渡す方法(今回のご質問内容ですと、こちらが手軽)。 4fs.createReadStream('src.txt').pipe(fs.createWriteStream('dest.txt')); 5 6// 2. 昔、書いた愚直にイベントリスナでコピーする方法(1.と同じ様なことをやっています) 7var copyFile = ( srcFile, dstFile, callback ) => { 8 var stat = fs.statSync( srcFile ), newFile, oldFile; 9 if( fs.existsSync( srcFile ) && stat.isFile() ) { 10 newFile = fs.createWriteStream( dstFile ); // to 11 oldFile = fs.createReadStream( srcFile ); // from 12 oldFile.addListener("data", (chunk) => { 13 newFile.write(chunk); 14 }); 15 oldFile.addListener("close",() => { 16 newFile.end(); 17 if(callback) { 18 callback(); 19 } 20 }); 21 } 22} 23

#実機試験試験結果:

手元の RaspberryPi3B+ で実験しました。

  1. ご質問のコード(エラーで停止)
  2. 回答させていただいた pipe() の方法(コピー成功)

※コード内にある console.time() 〜 console.timeEnd() は 2. において追加しました。
非同期であるため意味のないコード(処理開始された時点での反応速度)であり、実際は数分の時間を要しました。

RaspberryPi3B+

子プロセスを起動してコマンドラインを叩く方法

本題の fs からは離れますが、child_processcp コマンドも試しました。
バイナリアプリケーションに委譲するのでメモリ管理は不要との考えです

javascript

1const {exec} = require('child_process'); 2 3let cpCommand = ( file1, file2 ) => `cp ${file1} ${file2}`; 4 5let start = Date.now(); 6exec(cpCommand("test.txt", "test2.txt"), (error, stdout, stderr) => { 7 if (error) { 8 console.error(`exec error: ${error}`); 9 return; 10 } 11 console.log(`time: ${Date.now()-start} [msec]`); 12 console.log(`stdout: ${stdout}`); 13 console.error(`stderr: ${stderr}`); 14}); 15// time: 208008 [msec] 16// stdout: 17// stderr:

SDカードから読み、同一SDカードに複製するのに約5分かかりました。
microSDHC-I での複製は1分あたり500MBが目安かもしれません。
SSDドライブを利用するなど、ハードウェア性能を向上させる方法はあると思いますが、試していません

RaspberryPi は普通のLinuxマシンではありますが、ハードウェア性能は低いので、取り扱うファイルはサイズ上限を定めてシステム構築/運用するのが良いかもしれません。
500MBを超えると、正直、辛いと思います

投稿2020/05/20 00:52

編集2020/05/22 22:14
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuji_0055

2020/05/20 07:24 編集

ありがとうございます。以下のようにNODE_OPTIONSに--max-old-space-size=2048を付けて実行しました。 NODE_OPTIONS=--max-old-space-size=2048 node test.js しかしながら、また同じエラーが発生してしまいます。2048という数値が間違っているのでしょうか...
AkitoshiManabe

2020/05/20 08:50

> 2048という数値が間違っているのでしょうか... node --help でオプションを見ると Mbyte 単位での指定なので、 2GB 指定になっていますね。 --max-old-space-size (max size of the old space (in Mbytes)) ちなみに、ストリームで扱う案も追記しました。
fuji_0055

2020/05/22 22:47

そうなんですか...ラズパイ3ではメモリが苦しそうなのでこのような処理はラズパイ4に任せたいところですね。ありがとうございました。
guest

0

MacOSで動かしてみましたが、全く問題ありませんでした。
ソースに問題はないですね。
$ node -v
v12.16.1

Javascript

1const fs = require('fs'); 2const path = require('path'); 3fs.copyFileSync(path.join(__dirname, 'test.txt'), 4 path.join(__dirname, 'test2.txt'));

イメージ説明

投稿2020/05/19 15:15

technocore

総合スコア7337

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuji_0055

2020/05/19 22:43

ありがとうございます。MacOSで動くということはNode.jsの設定に問題があるのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問