改行コードとは?種類・使い方・プログラミング言語別の書き方を徹底解説
テキストファイルを開いたとき、「なぜか一行につながって表示されてしまう」「行末に謎の記号が表示される」「この設定ファイル、Windowsで作ったらLinuxで動かないぞ?」——。
これらの問題の多くは、「改行コード」の違いに起因しています。普段意識することは少ないかもしれませんが、改行コードはテキストデータの扱いにおいて非常に重要な要素です。特に、異なるOS間でファイルをやり取りしたり、プログラミングを行う際には、改行コードの知識が不可欠となります。
この記事では、改行コードの基本的な概念から、種類、OSごとの違い、確認・変換方法、そして主要なプログラミング言語での具体的な扱い方まで、約5000語というボリュームで徹底的に解説します。この一冊を読むことで、改行コードに関するあなたの疑問は解消されるはずです。
1. はじめに:目に見えない重要な文字「改行コード」
私たちは文章を書くとき、区切りたい場所でエンターキー(あるいはリターンキー)を押します。すると、カーソルや文字が次の行の先頭に移動し、見た目上の「改行」が行われます。これは当たり前の操作ですが、コンピュータのテキストファイルでは、この「改行」をどのように表現しているのでしょうか?
実は、テキストファイルの中では、私たちがキーボードで入力した文字だけでなく、「改行」という操作も特定の「文字データ」として記録されています。この文字こそが「改行コード」です。
改行コードは、画面に表示される「A」や「B」、「あ」や「い」といった文字とは異なり、通常は画面上では目に見えません。しかし、ファイルの中ではしっかりとデータとして存在し、テキストの構造を区切り、人間にとって読みやすい形(複数行に分かれた状態)で表示するために不可欠な役割を果たしています。
改行コードは「制御文字」と呼ばれる特殊な文字の一種です。制御文字は、文字そのものを表示するのではなく、プリンターや端末、ファイルなどの動作を制御するために使われる文字です。改行コードは、まさに「次の行に移る」という表示や印字の動作を制御するためのコードなのです。
この目に見えない改行コードですが、実はいくつかの種類があり、利用しているOSや環境によって標準的に使われるものが異なります。この違いが、異なる環境間でテキストファイルをやり取りした際に様々な問題を引き起こす原因となります。
2. 改行コードとは?基本概念を深掘り
2.1. 改行の定義:画面上の表示とファイル内のデータ
私たちがテキストエディタやワープロソフトで文章を入力する際に「改行する」という操作は、大きく分けて二つの意味合いを持ちます。
- 画面上の表示・レイアウトとしての改行: テキストエディタやブラウザなどが、特定の文字コード(改行コード)を検出した際に、表示領域を次の行に移す処理。これはあくまでアプリケーションが行う表示処理であり、ファイルの中身そのものではありません。
- ファイル内の制御文字としての改行: テキストファイルの中に、行の区切りを示すデータ(改行コード)を挿入する操作。これはファイルの内容そのものを変更するもので、このデータがあるおかげで、様々なアプリケーションがその箇所を「行の区切り」として認識できます。
改行コードが指すのは、主に後者の「ファイル内の制御文字」です。テキストファイルは、基本的に文字が一次元的に並んだデータ構造をしています。その並びの中に、行の区切りを示す「改行コード」が挿入されることで、ファイルが複数の「行」に構造化されるのです。
例えば、「こんにちは\nようこそ」という文字列がファイルに保存されているとします(ここで「\n」は改行コードを便宜的に表しています)。コンピュータはこのファイルを、単に「こ」「ん」「に」「ち」「は」「\n」「よ」「う」「こ」「そ」という文字の並びとして認識します。これをテキストエディタが開くと、「\n」というコードを検出した箇所で表示を次の行に移す、という処理を行います。結果として、画面上では以下のように表示されます。
こんにちは
ようこそ
このように、改行コードはファイルの中にある「目印」のようなものであり、その目印をどう解釈して表示するかは、テキストエディタなどのアプリケーションに委ねられています。
2.2. 改行コードの役割
改行コードの主な役割は以下の通りです。
- テキストファイルの構造化: 文字の一次元的な並びを、行という単位で区切ることで、ファイルに構造を与えます。これにより、特定の行を読み込んだり、行ごとに処理を行ったりすることが可能になります。
- 可読性の向上: 人間が文章を読む際には、行が分かれている方が圧倒的に読みやすくなります。改行コードがあることで、テキストデータは人間にとって理解しやすい形で表示されます。
- コマンドやスクリプトの区切り: プログラミングのソースコードや設定ファイル、シェルスクリプトなどでは、改行コードがコマンドやステートメントの区切りとして機能することがあります。
2.3. 目に見えない文字、制御文字
前述の通り、改行コードは通常、テキストエディタでそのまま表示されることはありません(設定によって表示させることは可能)。これは、改行コードが「表示可能な文字」ではなく「制御文字」であるためです。
制御文字は、コンピュータの初期の段階、特にテレタイプ端末やラインプリンターを制御するために生まれました。例えば、プリンターの用紙を送る、印字位置を先頭に戻す、といった操作を、データの中に特定のコードを含めることで指示していたのです。
改行コードも、これらの制御文字の一つとして標準化されました。最も一般的な改行コードは、ASCII (American Standard Code for Information Interchange) という文字コード体系の中に定義されています。
- LF (Line Feed): ASCIIコードで10番 (
0x0A
, 16進数) に割り当てられています。プリンターで「紙を一行分送る」という動作に由来します。 - CR (Carriage Return): ASCIIコードで13番 (
0x0D
, 16進数) に割り当てられています。タイプライターで「印字ヘッドを左端(行の先頭)に戻す」という動作に由来します。
この二つの制御文字が、異なるOSで採用される改行コードの基礎となっています。
3. 改行コードの種類:CR, LF, CRLF
さて、改行コードにはいくつかの種類があると述べましたが、主に以下の3つが代表的です。
- CR (Carriage Return)
- LF (Line Feed)
- CRLF (Carriage Return + Line Feed)
これらの違いは、どのOSが標準として採用しているかに関係しています。
3.1. LF (Line Feed) – \n
- 意味: 「改行(次の行に進む)」
- ASCIIコード: 10 (16進数:
0x0A
) - プログラミング言語での表現:
\n
(多くの言語) - 主な使用OS:
- UNIX
- Linux
- macOS (OS X 以降)
- Android
LFは、現在の多くのオペレーティングシステムで標準的に使用されている改行コードです。その名の通り、プリンターが紙を一行分繰り出す動作に由来します。これにより、印字位置が現在の行から次の行へ移動します。
UNIXが開発された当初からLFが改行コードとして採用され、その後のLinuxやmacOSといったUNIX系のOSでも引き継がれています。これらのOSでテキストファイルを作成すると、特別な設定をしない限り、行末にはLFコードが挿入されます。
プログラミング言語の文字列リテラルで改行を表す際によく使われる \n
は、このLFコードを表しています。
3.2. CR (Carriage Return) – \r
- 意味: 「復帰(行頭に戻る)」
- ASCIIコード: 13 (16進数:
0x0D
) - プログラミング言語での表現:
\r
(多くの言語) - 主な使用OS:
- Classic Mac OS (Mac OS 9 以前)
CRは、タイプライターの「キャリッジ(印字位置)」を左端に戻す動作に由来します。つまり、改行はせず、単に同じ行の先頭に戻るだけです。
歴史的には、電信やテレタイプ端末などで、受信側がプリンターの印字位置を制御するために使われました。
コンピュータのOSとしては、Mac OS 9以前のClassic Mac OSが標準の改行コードとしてCRを採用していました。しかし、Mac OS X (現在のmacOS) がUNIXベースになってからは、標準の改行コードがLFに変更されています。現在、CR単独で改行コードとして使われることは非常に稀です。
プログラミング言語の文字列リテラルで \r
と表現されるのは、このCRコードです。
3.3. CRLF (Carriage Return + Line Feed) – \r\n
- 意味: 「復帰してから改行(行頭に戻り、次の行に進む)」
- ASCIIコード: 13 + 10 (16進数:
0x0D 0x0A
) - プログラミング言語での表現:
\r\n
(多くの言語) - 主な使用OS:
- MS-DOS
- Windows
CRLFは、CRとLFをこの順序で組み合わせた改行コードです。タイプライターの動作をより忠実に模倣したものです。「行の先頭に戻る(CR)」と「紙を一行送る(LF)」という二つの動作を組み合わせて、完全な「改行」を実現しようとしたことに由来します。
MS-DOSで標準の改行コードとして採用され、その後継であるWindowsでも引き継がれています。Windowsでメモ帳などのテキストエディタを使ってファイルを作成すると、各行の末尾にはCRLFコードが挿入されます。
プログラミング言語の文字列リテラルで \r\n
と表現されるのは、このCRLFコードです。
3.4. その他の改行関連コード(補足)
主要な改行コードは上記の3種類ですが、Unicodeなどの文字コード体系には、他にも改行や段落の区切りを示す文字が定義されています。
- NEL (Next Line): U+0085。EBCDICという文字コード体系に由来する改行文字。Shift_JISなど、一部のマルチバイト文字コードでも互換性のために含まれていることがあります。
- LS (Line Separator): U+2028。Unicodeで定義された「行区切り文字」。明示的に行を区切りたいが、新しい段落を開始したくない場合などに使われます。
- PS (Paragraph Separator): U+2029。Unicodeで定義された「段落区切り文字」。新しい段落を開始したい場合に使われます。
これらのコードは、特定の場面(例えば、リッチテキスト形式の内部表現や、特定の規格に準拠したデータなど)で使われることはありますが、一般的なプレーンテキストファイルで改行コードとして使われることは稀です。ほとんどのテキストエディタやOSでは、CR, LF, CRLFのいずれかを標準として扱います。一般的な用途で「改行コード」と言う場合は、通常CR, LF, CRLFのいずれかを指します。
4. なぜ改行コードの種類が問題になるのか?
主要な改行コードがOSによって異なることは、特に異なるOS間でファイルを共有したり、開発を行ったりする際に様々な問題を引き起こす可能性があります。
4.1. 互換性の問題:表示崩れと実行エラー
これが最も一般的な問題です。
-
表示崩れ: WindowsでCRLF改行で作成したテキストファイルを、LF改行を標準とするUNIX系OS(Linux, macOSなど)のテキストエディタで開くと、改行コードが正しく認識されず、ファイル全体が一行につながって表示されてしまうことがあります。逆に、UNIX系OSでLF改行で作成したファイルを、CRLF改行を標準とする古いバージョンのWindowsメモ帳などで開くと、LFが単なる「紙送り」と解釈され、行末に「□」のような謎の記号(CRが正しく解釈されない)が表示されたり、やはり表示が乱れたりすることがありました。(最近の多くのテキストエディタは、CRLF, LF, CRのいずれも適切に解釈して表示するようになっていますが、互換性のない環境や古いツールでは問題が起こり得ます。)
-
スクリプト実行時の問題: 特にシェルスクリプトなどの実行可能ファイルで問題が起こりやすいです。Windowsで作成・編集したシェルスクリプト(CRLF改行)をLinuxなどのUNIX系環境に持ってきて実行しようとすると、「コマンドが見つかりません」といったエラーが出たり、shebang行 (
#!/bin/bash
など) が正しく解釈されなかったりすることがあります。これは、スクリプトの各行の末尾に本来の改行コードであるLFだけでなく、余計なCRコードが付いているため、コマンド名やパスが「command\r
」のように解釈されてしまうためです。PythonやPerlなどのスクリプトでも同様の問題が発生することがあります。
4.2. テキストエディタでの表示と認識
多くの高機能なテキストエディタは、ファイルを開く際に改行コードの種類を自動的に判別し、適切に表示する機能を備えています。また、ステータスバーなどに現在のファイルの改行コード(CRLF, LF, CRなど)を表示してくれます。
しかし、エディタによっては判別が不十分だったり、ユーザーが意図しない改行コードで保存してしまったりすることがあります。例えば、CRLFのファイルをLFとして開いて編集・保存すると、意図せずLFファイルに変換されてしまうこともあります。改行コードの種類を意識し、エディタの機能を使って確認・変換できることが重要です。
4.3. バージョン管理システム (Git) での問題
ソフトウェア開発において、バージョン管理システム(VCS)は不可欠です。最も広く使われているGitでも、改行コードの違いは問題となります。
チーム内で異なるOSを使っているメンバーがいる場合、同じファイルを編集しても、改行コードが異なるだけでGitは「差分がある」と判断してしまいます。これは、CRLFとLFではファイルの内容がバイナリ的に異なるためです。
例えば、WindowsユーザーがLF改行のファイルを編集してCRLF改行で保存し、LinuxユーザーがそのファイルをLF改行で保存し直す、といったことが繰り返されると、実際のコード変更はわずかでも、改行コードの差分によって大量の差分が表示され、変更履歴がノイズだらけになってしまいます。これはコードレビューを困難にし、コンフリクト発生のリスクを高めます。
Gitには、この問題を解決するための core.autocrlf
という設定がありますが、その設定を理解して適切に運用しないと、かえって混乱を招くこともあります。
5. 改行コードの確認方法と変換方法
改行コードによる問題を解決するためには、まずファイルの改行コードを確認し、必要に応じて目的の改行コードに変換するスキルが必要です。
5.1. テキストエディタでの確認・表示・変換
多くのプログラマー向けの高機能テキストエディタは、改行コードの確認と変換機能を備えています。
-
確認:
- VS Code: 画面右下のステータスバーに現在の改行コード(CRLFまたはLF)が表示されます。ここをクリックすると変換メニューが表示されます。
- Sublime Text / Atom: 画面右下のステータスバーに表示されます。
- Notepad++: 画面右下のステータスバーに表示されます。メニューの「編集」→「行末コード変換」で変換も可能です。
- サクラエディタ: 画面右下のステータスバーに「DOS(CR+LF)」「Unix(LF)」「Mac(CR)」のように表示されます。メニューの「名前を付けて保存」ダイアログで改行コードを選択できます。
- Vim: コマンドモードで
:set fileformat?
と入力すると、現在の改行コード(fileformat=dos
ならCRLF、fileformat=unix
ならLF、fileformat=mac
ならCR)が表示されます。 - Emacs: 画面下部のモードラインに
(Unix)
(LF),(DOS)
(CRLF),(Mac)
(CR) のように表示されます。
-
不可視文字(制御文字)の表示: 多くのエディタには、改行コードを含む不可視文字を記号などで表示する機能があります。これにより、ファイル内にどのような改行コードが存在するかを視覚的に確認できます。
- VS Code: 設定で
editor.renderControlCharacters
を有効にする、または拡張機能を使用。 - Notepad++: メニューの「表示」→「記号を表示」→「改行とタブを表示(CR+LF)」や「全ての文字を表示」を選択。
- サクラエディタ: メニューの「表示」→「各種制御文字/空白」で設定。
- Vim: コマンドモードで
:set list
と入力すると、改行コードが$
などで表示されます。
- VS Code: 設定で
-
変換:
- 多くのエディタでは、メニュー項目(例: 「編集」→「行末コード変換」、「ファイル」→「名前を付けて保存」ダイアログでの選択など)や、ステータスバーの表示をクリックすることで、開いているファイルの改行コードを別の種類に変換して保存できます。
5.2. コマンドラインツールでの確認・変換 (Unix/Linux/macOS)
Unix/Linux/macOS環境では、コマンドラインツールを使って改行コードを確認・変換できます。
-
cat -vE
:
cat
コマンドにオプションを付けることで、不可視文字を表示できます。-v
: 不可視文字を表示 (M-
や^
を使った形式)-E
: 各行の末尾に$
を表示(LFがある位置が分かりやすい)
CRLFのファイル (\r\n
) を表示すると、行末が^M$
のように表示されます (^M
がCRを表します)。LFのファイル (\n
) なら、行末が単に$
と表示されます。
“`bash
CRLFのファイルを確認
cat -vE windows_file.txt
LFのファイルを確認
cat -vE unix_file.txt
“` -
od -c
:
od
(octal dump) コマンドは、ファイルの内容を様々な形式(この例では文字形式-c
)でダンプします。改行コードはエスケープシーケンスで表示されます。\n
: LF\r
: CR
“`bash
ファイルの内容を文字形式で表示
od -c your_file.txt
例: CRLFファイルの一部
0000000 h e l l o \r \n w o r l d \r \n
例: LFファイルの一部
0000000 h e l l o \n w o r l d \n
“`
-
file
:
file
コマンドはファイルの種類を判定しますが、テキストファイルの場合は改行コードについても言及することがあります。
bash
file your_file.txt
# 例: ASCII text, with CRLF line terminators
# 例: ASCII text
ただし、ASCII text
とだけ表示される場合もあり、LFかどうかの判定には使えますが、CRLFかどうかの判定には-vE
や-c
の方が確実です。 -
nkf
(Network Kanji Filter):
日本語環境では非常に強力なツールです。文字コード変換だけでなく、改行コード変換も得意とします。- 改行コードの確認 (
-g
オプション):
bash
nkf -g your_file.txt
# 結果例: LF, CRLF, CR など - 改行コードの変換 (
-Lw
はLF,-Lu
はCRLF,-Lm
はCR):
bash
# CRLFからLFに変換して別ファイルに保存
nkf -Lu your_file_crlf.txt > your_file_lf.txt
# LFからCRLFに変換して上書き
nkf -Lw your_file_lf.txt --overwrite
- 改行コードの確認 (
-
dos2unix
/unix2dos
:
これらのコマンドは、ファイル名の通り、CRLF (dos) と LF (unix) の間で相互変換を行うための専用ツールです。多くのLinuxディストリビューションで利用できます。
bash
# CRLF (dos) から LF (unix) へ変換 (ファイルを上書き)
dos2unix your_file_crlf.txt
# LF (unix) から CRLF (dos) へ変換 (ファイルを上書き)
unix2dos your_file_lf.txt
これらは最もシンプルで一般的な改行コード変換ツールです。
5.3. コマンドラインツールでの確認・変換 (Windows PowerShell)
PowerShellでも、簡単なスクリプトで改行コードを確認・変換できます。
-
確認:
テキストファイルの内容をそのまま表示すると、PowerShellは改行コードを解釈して表示するため、種類の判別は難しいです。バイナリとして読み込むか、特殊文字をエスケープして表示する必要があります。
簡単な確認方法としては、ファイルを行ごとに読み込み、各行の末尾にCR(\r
)が含まれているかを確認する方法があります。
powershell
# CRLFファイルの場合、各行の末尾に `r` が表示される
Get-Content your_file.txt | ForEach-Object { "$_`r" }
# LFファイルの場合、各行の末尾に何も表示されない
Get-Content your_file.txt | ForEach-Object { "$_`r" }
より厳密には、ファイルのバイト列を確認する必要があります。
powershell
# 最初の数バイトと改行コード付近のバイトを確認
Format-Hex -Path your_file.txt -Count 50
# 16進数で 0D 0A がCRLF、0A がLF -
変換:
Get-Content
で読み込み、Out-File
で書き出す際に、改行コードを指定できます。Out-File
のデフォルトのエンコーディングと改行コードは、PowerShellのバージョンや環境によって異なりますが、通常はシステムの標準改行コード(WindowsならCRLF)になります。明示的に改行コードを指定するには-NoNewline
オプションを使ってから、自分で"
rn"
や"
n”を追加します。
n” | Add-Content your_file_lf.txt # 各行の後にLFを追加
```powershell
# LFファイルとして保存
Get-Content your_file.txt | ForEach-Object { $_ } | Out-File -Path your_file_lf.txt -Encoding UTF8 -NoNewline
"
# ※ただし、これは行ごとにLFを追加するだけで、元の改行コードを考慮しないため、複数行まとめて処理する方が良い。CRLFファイルをLFに変換して保存 (より実用的)
(Get-Content your_file_crlf.txt -Raw) -replace “
r
n”, “`n” | Out-File -Path your_file_lf.txt -Encoding UTF8LFファイルをCRLFに変換して保存
(Get-Content your_file_lf.txt -Raw) -replace “
n", "
rn" | Out-File -Path your_file_crlf.txt -Encoding UTF8
-Raw
```オプションはファイル全体を単一の文字列として読み込むため、置換処理が効率的です。
-Encoding UTF8` は文字化けを防ぐために重要です。
5.4. プログラミング言語を使った確認・変換
後述の「プログラミング言語における改行コードの扱い」で詳しく説明しますが、ほとんどのプログラミング言語には、ファイルの内容を読み込み、文字列処理で改行コードを置換し、目的の改行コードでファイルに書き出す機能があります。
これは、ファイルの内容をプログラムで操作する際に非常に強力な方法です。特に、複数のファイルをまとめて処理したり、特定の条件で改行コードを変更したりする場合に便利です。
6. プログラミング言語における改行コードの扱い
プログラミングにおいて、改行コードは文字列操作やファイル入出力の際に意識する必要があります。
6.1. 文字列リテラルでの改行表現
多くのプログラミング言語では、文字列リテラル内で特別なエスケープシーケンスを使って制御文字を表現します。改行コードのLFとCRも同様です。
\n
: LF (Line Feed)。多くの言語で「改行」として最も一般的に使われます。\r
: CR (Carriage Return)。\r\n
: CRLF。CRの直後にLFを続けることで表現します。
例えば、PythonやJava、C#など、多くの言語で "Hello\nWorld"
という文字列は、”Hello” の後にLF改行コードが続き、その後に “World” が続く文字列データとなります。これをテキストファイルに書き出すと、ファイルの中には実際のLFコード (0x0A) が記録されます。
6.2. システム依存の改行コードの取得
プログラムを実行するOSによって標準の改行コードが異なるため、ファイルに書き出す際にそのOSの標準改行コードを使いたい場合があります。多くの言語では、システム依存の改行コードを取得するための方法が提供されています。
- Python:
os.linesep
- Java:
System.lineSeparator()
(Java 7以降) またはSystem.getProperty("line.separator")
- C#:
Environment.NewLine
- Node.js:
os.EOL
- PHP:
PHP_EOL
定数 - Ruby:
$OUTPUT_RECORD_SEPARATOR
($\
), デフォルトは\n
だが変更可能。または$/
($-0
) は入力レコード区切りで、デフォルトは\n
だが、ファイル全体を読み込む場合はnilになるなど少し複雑。一般的に出力には$\
を使うか、明示的に\n
や\r\n
を使う方が分かりやすい。 - Go:
\n
が一般的だが、クロスプラットフォーム対応でOS標準を使いたい場合は"os"
パッケージのos.WriteFile
やbufio.NewWriter
などで対応するか、自分で"runtime"
パッケージなどで判定して使い分ける必要がある。標準ライブラリには直接的なlinesep
的な定数はない。
これらの定数やプロパティを利用することで、実行環境に合わせた改行コードを動的に取得し、プログラム内で利用できます。
6.3. ファイル入出力時の注意点:テキストモードとバイナリモード
多くのプログラミング言語やランタイムシステムでは、ファイルのオープン時に「テキストモード」と「バイナリモード」を選択できます。このモードによって、改行コードの扱いが大きく異なります。
-
テキストモード:
- 主に人間が読むことを想定したテキストファイルを扱うためのモードです。
- 改行コードの自動変換: テキストモードでファイルを開くと、OSの標準的な改行コードと、プログラム内部での標準的な改行表現(多くの言語では
\n
)の間で、改行コードの自動変換が行われることがあります。- Windows: ファイルから読み込む際、CRLF (
\r\n
) をプログラム内部のLF (\n
) に自動変換します。ファイルに書き出す際、プログラム内部のLF (\n
) をCRLF (\r\n
) に自動変換します。これは、ファイルシステム上はCRLFだが、プログラム内ではシンプルにLFとして扱えるようにするための親切機能(とも言えるし、トラブルの元とも言える)。 - Unix/Linux/macOS: 通常、自動変換は行われません。ファイル内のLF (
\n
) はそのままプログラム内部のLF (\n
) として扱われ、プログラム内部のLF (\n
) はファイルにそのままLF (\n
) として書き出されます。CR (\r
) は特別な扱いを受けません。
- Windows: ファイルから読み込む際、CRLF (
- エンコーディング: テキストモードで開く場合、文字エンコーディング(UTF-8, Shift_JISなど)を指定したり、ランタイムのデフォルトエンコーディングが使われたりします。読み書きの際に、指定されたエンコーディングに従ってバイト列と文字(文字列)の変換が行われます。
-
バイナリモード:
- テキストファイルだけでなく、画像ファイル、実行ファイルなど、あらゆる種類のファイルをバイト列としてそのまま扱うためのモードです。
- 改行コードの自動変換なし: バイナリモードでファイルを開くと、改行コードを含むファイルの内容が一切変換されずに、そのままのバイト列として読み書きされます。CRLFは
0x0D 0x0A
のバイト列として、LFは0x0A
のバイト列として、ファイルから読み込んだバイトがそのままプログラムに渡され、プログラムが出力したバイトがそのままファイルに書き込まれます。 - エンコーディング: バイナリモードでは、エンコーディングの概念はありません。あくまでバイト列の入出力です。
ファイル入出力時の選択:
一般的に、人間が読むためのテキストファイル(設定ファイル、ログファイルなど)を扱う場合はテキストモードを使用します。ただし、異なるOS間でファイルを厳密に扱いたい場合や、改行コードの種類を自分で完全に制御したい場合は、バイナリモードで読み書きし、プログラム内でバイト列として改行コードを処理する方が安全な場合もあります(例: 0x0D 0x0A
のバイト列を 0x0A
のバイト列に置換するなど)。しかし、多くの場合はテキストモードとOS標準の改行コード変換機能を理解して利用する方がシンプルです。
6.4. 言語別の具体的な書き方
以下に、主要なプログラミング言語での改行コードの扱いの具体例を示します。
Python:
“`python
import os
文字列リテラルでの改行
s1 = “Hello\nWorld” # LF
s2 = “Hello\rWorld” # CR
s3 = “Hello\r\nWorld” # CRLF
print(f”s1 (LF): {repr(s1)}”) # repr() でエスケープシーケンスを表示
print(f”s2 (CR): {repr(s2)}”)
print(f”s3 (CRLF): {repr(s3)}”)
システム依存の改行コード
print(f”System line separator: {repr(os.linesep)}”)
ファイル書き込み (テキストモード)
デフォルトでは OS の標準改行コードで書き込まれる
with open(“output_default.txt”, “w”, encoding=”utf-8″) as f:
f.write(“Line 1\n”)
f.write(“Line 2” + os.linesep) # os.linesep を明示的に使う
LF で書き込みたい場合
with open(“output_lf.txt”, “w”, newline=”\n”, encoding=”utf-8″) as f:
f.write(“Line 1\n”)
f.write(“Line 2\n”)
CRLF で書き込みたい場合
with open(“output_crlf.txt”, “w”, newline=”\r\n”, encoding=”utf-8″) as f:
f.write(“Line 1\n”) # ここでの \n はnewline引数によって \r\n に変換される
f.write(“Line 2\r\n”)
バイナリモードでの書き込み (変換なし)
with open(“output_binary.bin”, “wb”) as f:
f.write(b”Binary data\r\n”) # CRLF のバイト列をそのまま書き込む
f.write(b”Next line\n”) # LF のバイト列をそのまま書き込む
ファイル読み込み (テキストモード)
デフォルトでは OS の標準改行コードに合わせて変換される (Windows: CRLF->LF)
newline=None (デフォルト) の場合、CRLF, LF, CR いずれも \n に変換される
with open(“output_default.txt”, “r”, encoding=”utf-8″) as f:
content = f.read()
print(f”Read (default): {repr(content)}”)
改行コードを変換せずに読み込みたい場合 (newline=” または newline=None)
newline=” の場合、改行はそのまま読み込まれる(\n, \r, \r\n がそのまま文字列として取得できる)
ただし、行区切りでの読み込み (.readline(), .readlines(), イテレーション) が期待通りにならない可能性がある
with open(“output_crlf.txt”, “r”, newline=””, encoding=”utf-8″) as f:
content = f.read()
print(f”Read (no conversion): {repr(content)}”)
バイナリモードでの読み込み (変換なし)
with open(“output_binary.bin”, “rb”) as f:
binary_content = f.read()
print(f”Read (binary): {binary_content}”) # バイト列として表示
``
open()
Pythonの関数の
newline引数は、テキストモードでの改行コードの扱いに影響します。
newline=None
*(デフォルト): 読み込み時はCRLF, LF, CRのいずれもLF(
\n)に変換されます。書き込み時は
\nがOS標準の改行コードに変換されます。
newline=’
*'
: 読み込み・書き込みともに変換を行いません。ファイル内の改行コードはそのまま文字列内に現れます。.readlines()
などはLF, CR, CRLFのいずれでも行を分割します。
* newline='\n'
, newline='\r'
, newline='\r\n'
: 読み込み時は指定した改行コードのみを\n
に変換します。書き込み時は\n
を指定した改行コードに変換します。
Java:
“`java
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
public class NewLineExample {
public static void main(String[] args) throws IOException {
// 文字列リテラルでの改行
String s1 = "Hello\nWorld"; // LF
String s2 = "Hello\rWorld"; // CR
String s3 = "Hello\r\nWorld"; // CRLF
System.out.println("s1 (LF): " + s1.replace("\n", "\\n").replace("\r", "\\r"));
System.out.println("s2 (CR): " + s2.replace("\n", "\\n").replace("\r", "\\r"));
System.out.println("s3 (CRLF): " + s3.replace("\n", "\\n").replace("\r", "\\r"));
// システム依存の改行コード
System.out.println("System line separator: " + System.lineSeparator().replace("\n", "\\n").replace("\r", "\\r"));
// ファイル書き込み (テキストモード - BufferedWriter/PrintWriter)
// println() メソッドは System.lineSeparator() を使用する
// write() メソッドは引数に与えられた文字列をそのまま書き込む
try (BufferedWriter writer = new BufferedWriter(new FileWriter("output_default.txt", StandardCharsets.UTF_8))) {
writer.write("Line 1");
writer.newLine(); // OS 標準の改行コードを書き込む
writer.write("Line 2\n"); // LF を書き込む
writer.write("Line 3\r\n"); // CRLF を書き込む
}
// ファイル書き込み (PrintWriter)
// println() は OS 標準の改行コードを使用
try (PrintWriter writer = new PrintWriter("output_default_pw.txt", StandardCharsets.UTF_8)) {
writer.println("Line 1");
writer.println("Line 2");
}
// 特定の改行コードで書き込みたい場合
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("output_lf.txt"), StandardCharsets.UTF_8))) {
writer.write("Line 1\n");
writer.write("Line 2\n");
}
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("output_crlf.txt"), StandardCharsets.UTF_8))) {
writer.write("Line 1\r\n");
writer.write("Line 2\r\n");
}
// ファイル読み込み (テキストモード - BufferedReader)
// readLine() メソッドは、CR, LF, CRLF のいずれも行末として認識し、行末記号を取り除いた文字列を返す
try (BufferedReader reader = new BufferedReader(new FileReader("output_default.txt", StandardCharsets.UTF_8))) {
String line;
System.out.println("\nReading line by line:");
while ((line = reader.readLine()) != null) {
System.out.println("Line: " + line.replace("\n", "\\n").replace("\r", "\\r")); // readLine() は改行コードを含まない
}
}
// ファイル全体を文字列として読み込み
// Files.readString (Java 11+) や Stream を使うと、ファイル内の改行コードがそのまま文字列に含まれる (テキストモード)
String contentDefault = Files.readString(Paths.get("output_default.txt"), StandardCharsets.UTF_8);
System.out.println(f"\nRead (default): {contentDefault.replace("\n", "\\n").replace("\r", "\\r")}");
String contentLF = Files.readString(Paths.get("output_lf.txt"), StandardCharsets.UTF_8);
System.out.println(f"Read (LF): {contentLF.replace("\n", "\\n").replace("\r", "\\r")}");
String contentCRLF = Files.readString(Paths.get("output_crlf.txt"), StandardCharsets.UTF_8);
System.out.println(f"Read (CRLF): {contentCRLF.replace("\n", "\\n").replace("\r", "\\r")}");
// バイナリモードでの読み込み
byte[] binaryContent = Files.readAllBytes(Paths.get("output_binary.bin")); // Path は適切に指定
System.out.println("\nRead (binary):");
for (byte b : binaryContent) {
System.out.printf("%02X ", b); // 16進数で表示
}
System.out.println();
}
}
``
BufferedReader.readLine()
Javaのは、CR、LF、CRLFのいずれの改行コードも正しく行末として認識し、返される文字列から改行コード自体は取り除かれます。これは、異なるOSで作成されたテキストファイルを読み込む際に便利な挙動です。
BufferedWriter.newLine()はOS標準の改行コードを書き込みます。
PrintWriter.println()も同様です。自分で特定の改行コードを書き込みたい場合は、
writer.write(“\n”)や
writer.write(“\r\n”)のように明示的に指定します。
Files.readStringや
Files.readAllLines(Java 11+) を使う場合、ファイル内の改行コードがどのように扱われるかはメソッドやバージョンによりますが、
readString` は通常テキストモードの変換(WindowsでCRLF->LFなど)を経て単一の文字列として返します。
C#:
“`csharp
using System;
using System.IO;
using System.Text;
public class NewLineExample
{
public static void Main(string[] args)
{
// 文字列リテラルでの改行
string s1 = “Hello\nWorld”; // LF
string s2 = “Hello\rWorld”; // CR
string s3 = “Hello\r\nWorld”; // CRLF
Console.WriteLine($"s1 (LF): {s1.Replace("\n", "\\n").Replace("\r", "\\r")}");
Console.WriteLine($"s2 (CR): {s2.Replace("\n", "\\n").Replace("\r", "\\r")}");
Console.WriteLine($"s3 (CRLF): {s3.Replace("\n", "\\n").Replace("\r", "\\r")}");
// システム依存の改行コード
Console.WriteLine($"System line separator: {Environment.NewLine.Replace("\n", "\\n").Replace("\r", "\\r")}");
// ファイル書き込み (テキストモード - StreamWriter)
// WriteLine() メソッドは Environment.NewLine を使用する
// Write() メソッドは引数に与えられた文字列をそのまま書き込む
using (StreamWriter writer = new StreamWriter("output_default.txt", false, Encoding.UTF8))
{
writer.WriteLine("Line 1"); // Environment.NewLine を書き込む
writer.Write("Line 2\n"); // LF を書き込む
writer.Write("Line 3\r\n"); // CRLF を書き込む
}
// 特定の改行コードで書き込みたい場合
// LF
using (StreamWriter writer = new StreamWriter("output_lf.txt", false, Encoding.UTF8))
{
writer.CoreNewLine = new char[] { '\n' }; // 書き込み時の改行コードを設定
writer.WriteLine("Line 1"); // LF で書き込まれる
writer.Write("Line 2\n"); // LF を書き込む
}
// CRLF
using (StreamWriter writer = new StreamWriter("output_crlf.txt", false, Encoding.UTF8))
{
writer.CoreNewLine = new char[] { '\r', '\n' }; // 書き込み時の改行コードを設定
writer.WriteLine("Line 1"); // CRLF で書き込まれる
writer.Write("Line 2\r\n"); // CRLF を書き込む
}
// ファイル読み込み (テキストモード - StreamReader)
// ReadLine() メソッドは、CR, LF, CRLF のいずれも行末として認識し、行末記号を取り除いた文字列を返す
Console.WriteLine("\nReading line by line:");
using (StreamReader reader = new StreamReader("output_default.txt", Encoding.UTF8))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine("Line: " + line.Replace("\n", "\\n").Replace("\r", "\\r")); // ReadLine() は改行コードを含まない
}
}
// ファイル全体を文字列として読み込み
// File.ReadAllText もテキストモード。OS標準の改行コード変換が適用される。
string contentDefault = File.ReadAllText("output_default.txt", Encoding.UTF8);
Console.WriteLine($"\nRead (default): {contentDefault.Replace("\n", "\\n").Replace("\r", "\\r")}");
string contentLF = File.ReadAllText("output_lf.txt", Encoding.UTF8);
Console.WriteLine($"Read (LF): {contentLF.Replace("\n", "\\n").Replace("\r", "\\r")}");
string contentCRLF = File.ReadAllText("output_crlf.txt", Encoding.UTF8);
Console.WriteLine($"Read (CRLF): {contentCRLF.Replace("\n", "\\n").Replace("\r", "\\r")}");
// バイナリモードでの読み込み
byte[] binaryContent = File.ReadAllBytes("output_binary.bin"); // ファイル名は適切に指定
Console.WriteLine("\nRead (binary):");
foreach (byte b in binaryContent)
{
Console.Write($"{b:X2} "); // 16進数で表示
}
Console.WriteLine();
// バイナリモードでの書き込み
File.WriteAllBytes("output_binary.bin", new byte[] { 0x41, 0x42, 0x43, 0x0D, 0x0A, 0x44, 0x45, 0x46, 0x0A }); // ABC<CRLF>DEF<LF>
}
}
``
StreamReader.ReadLine()
C#のもJavaと同様にCR, LF, CRLFのいずれも行末として認識し、改行コードを取り除きます。
StreamWriter.WriteLine()は
Environment.NewLineを使用します。
StreamWriter.CoreNewLineプロパティを使うと、
WriteLine()メソッドで出力される改行コードを制御できます。
File.ReadAllTextなど便利なメソッドもテキストモードで動作し、OS標準の改行コード変換を行います。バイナリモードは
File.Open(…, FileMode.Open, FileAccess.Read, FileShare.Read).Read(…)や
File.ReadAllBytes/
File.WriteAllBytes` などを使用します。
Node.js (JavaScript):
“`javascript
const os = require(‘os’);
const fs = require(‘fs’);
const path = require(‘path’);
// 文字列リテラルでの改行
let s1 = “Hello\nWorld”; // LF
let s2 = “Hello\rWorld”; // CR
let s3 = “Hello\r\nWorld”; // CRLF
console.log(s1 (LF): ${s1.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
console.log(s2 (CR): ${s2.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
console.log(s3 (CRLF): ${s3.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
// システム依存の改行コード
console.log(System line separator: ${os.EOL.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
const filePathDefault = path.join(__dirname, ‘output_default.txt’);
const filePathLF = path.join(__dirname, ‘output_lf.txt’);
const filePathCRLF = path.join(__dirname, ‘output_crlf.txt’);
const filePathBinary = path.join(__dirname, ‘output_binary.bin’);
// ファイル書き込み (テキストモード)
// fs.writeFileSync や fs.createWriteStream は、指定された encoding で文字列をバイト列に変換するが、
// デフォルトでは改行コードの自動変換は行われない。\n は 0x0A、\r\n は 0x0D 0x0A としてそのまま書き出される。
fs.writeFileSync(filePathDefault, “Line 1” + os.EOL + “Line 2\nLine 3\r\n”, ‘utf8’);
// LF で書き込みたい場合
fs.writeFileSync(filePathLF, “Line 1\nLine 2\n”, ‘utf8’);
// CRLF で書き込みたい場合
fs.writeFileSync(filePathCRLF, “Line 1\r\nLine 2\r\n”, ‘utf8’);
// バイナリモードでの書き込み (変換なし)
fs.writeFileSync(filePathBinary, Buffer.from([0x41, 0x42, 0x43, 0x0D, 0x0A, 0x44, 0x45, 0x46, 0x0A])); // ABC
// ファイル読み込み (テキストモード)
// fs.readFileSync や fs.readFile は、指定された encoding でバイト列を文字列に変換する。
// デフォルトでは改行コードの変換は行われない。ファイル内の改行コードがそのまま文字列に含まれる。
const contentDefault = fs.readFileSync(filePathDefault, ‘utf8’);
console.log(\nRead (default): ${contentDefault.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
const contentLF = fs.readFileSync(filePathLF, ‘utf8’);
console.log(Read (LF): ${contentLF.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
const contentCRLF = fs.readFileSync(filePathCRLF, ‘utf8’);
console.log(Read (CRLF): ${contentCRLF.replace(/\n/g, '\\n').replace(/\r/g, '\\r')}
);
// 行ごとに読み込む場合 (readline モジュールなどを使用)
// readline モジュールはデフォルトで \n または \r\n を行末として認識する
const readline = require(‘readline’);
const rl = readline.createInterface({
input: fs.createReadStream(filePathDefault),
crlfDelay: Infinity // このオプションで行末として \r\n, \n を認識
});
console.log(“\nReading line by line:”);
rl.on(‘line’, (line) => {
console.log(“Line: ” + line.replace(/\n/g, ‘\n’).replace(/\r/g, ‘\r’)); // 行末記号は含まれない
});
rl.on(‘close’, () => {
console.log(“Finished reading lines.”);
});
// バイナリモードでの読み込み
const binaryContent = fs.readFileSync(filePathBinary);
console.log(“\nRead (binary):”);
console.log(binaryContent); // Buffer オブジェクトとして表示
console.log(binaryContent.toString(‘hex’)); // 16進数文字列として表示
``
fs
Node.jsの標準モジュールは、ファイルシステムレベルでの改行コード自動変換を行いません。テキストモードでファイルを開いた場合でも、
\nはLF、
\r\nはCRLFとしてバイト列に変換され、そのままファイルに書き込まれます。読み込み時もファイル内の改行コードがそのまま文字列に含まれます。行ごとに読み込む場合は、
readlineモジュールなどを使用する必要があります。
readline` はデフォルトでLFとCRLFを行末として扱います。
C/C++:
“`c
include
include // For strerror
include // For errno
int main() {
// 文字列リテラルでの改行
const char s1 = “Hello\nWorld”; // LF
const char s2 = “Hello\rWorld”; // CR
const char* s3 = “Hello\r\nWorld”; // CRLF
// C/C++ にシステム依存の改行コードを取得する標準的な方法はない
// 環境によって \n がどう解釈されるかが変わる(テキストモードの場合)
// ファイル書き込み (テキストモード - "w" or "wt")
// Windows の MSVCRT などでは、テキストモードで \n を書き込むと \r\n に変換される
// Unix 系では、テキストモードで \n を書き込んでもそのまま \n が書き込まれる
FILE *fp_default = fopen("output_default.txt", "w"); // テキストモード
if (fp_default == NULL) {
perror("Error opening output_default.txt");
return 1;
}
fputs("Line 1\n", fp_default); // \n が OS 標準改行に変換される可能性あり
fputs("Line 2\r\n", fp_default); // \r\n はそのまま書き込まれる
fclose(fp_default);
// 明示的に LF を書き込みたい場合 (Unix 系では不要だが Windows ではバイナリモードを使う)
// Windows で LF を書きたい場合は バイナリモード + 自分で \n (0x0A) バイトを書き込む
FILE *fp_lf = fopen("output_lf.txt", "wb"); // バイナリモード
if (fp_lf == NULL) {
perror("Error opening output_lf.txt");
return 1;
}
fputs("Line 1", fp_lf); // 文字列をバイトとして書き込む
fputc('\n', fp_lf); // LF (0x0A) バイトを書き込む
fputs("Line 2", fp_lf);
fputc('\n', fp_lf);
fclose(fp_lf);
// 明示的に CRLF を書き込みたい場合 (Unix 系では \r\n をそのまま書き込む、Windows ではテキストモードで \n を使うかバイナリモード)
FILE *fp_crlf = fopen("output_crlf.txt", "w"); // Windows なら w で \n -> \r\n 変換を利用できる
if (fp_crlf == NULL) {
perror("Error opening output_crlf.txt");
return 1;
}
// Windows では \n が \r\n に変換される
fputs("Line 1\n", fp_crlf);
fputs("Line 2\n", fp_crlf);
// または、バイナリモードで \r\n バイトを直接書き込む
// FILE *fp_crlf_bin = fopen("output_crlf.txt", "wb");
// fputs("Line 1\r\n", fp_crlf_bin);
// fputs("Line 2\r\n", fp_crlf_bin);
// fclose(fp_crlf_bin);
fclose(fp_crlf);
// ファイル読み込み (テキストモード - "r" or "rt")
// Windows の MSVCRT などでは、テキストモードで \r\n を読み込むと \n に変換される
// Unix 系では、テキストモードで LF や CR を読み込んでもそのまま読み込まれる
FILE *fp_read_default = fopen("output_default.txt", "r"); // テキストモード
if (fp_read_default == NULL) {
perror("Error opening output_read_default.txt");
return 1;
}
char buffer[256];
printf("\nReading text file:\n");
while (fgets(buffer, sizeof(buffer), fp_read_default) != NULL) {
// fgets は改行コードも含めて読み込む (ただし Windows テキストモードでは \r\n は \n に変換される)
printf("Line: %s", buffer);
}
fclose(fp_read_default);
// バイナリモードでの読み込み ("rb") - 変換なし
FILE *fp_read_binary = fopen("output_binary.bin", "rb");
if (fp_read_binary == NULL) {
perror("Error opening output_read_binary.bin");
return 1;
}
printf("\nReading binary file:\n");
unsigned char byte;
while (fread(&byte, 1, 1, fp_read_binary) == 1) {
printf("%02X ", byte); // 16進数で表示
}
printf("\n");
fclose(fp_read_binary);
return 0;
}
``
fopen
C/C++の標準ライブラリ関数 (,
fputs,
fgetsなど) では、ファイルオープン時のモード文字列に
b(バイナリモード) を付けない場合(つまりテキストモード
r,
w,
aなど)、システムによって改行コードの自動変換が行われることがあります。特にWindowsでは、テキストモードでのLF(
\n)とCRLF(
\r\n)の間の自動変換がデフォルトで有効です。Unix系システムでは、テキストモードでも自動変換は行われません。クロスプラットフォームで改行コードを厳密に制御したい場合は、バイナリモード (
rb,
wb) でファイルを開き、プログラム内で
\n(0x0A) や
\r\n(0x0D 0x0A) のバイト列を直接扱う必要があります。C++の
fstream` も同様の挙動を示します。
PHP:
“`php
DEF
file_put_contents($filePathBinary, $binaryData);
// バイナリモード ‘rb’ で開き、バイト列を読み込む
$binaryContent = file_get_contents($filePathBinary);
echo “\nRead (binary):\n”;
for ($i = 0; $i < strlen($binaryContent); $i++) {
printf("%02X ", ord($binaryContent[$i])); // バイトを16進数で表示
}
echo "\n";
?>
``
file_get_contents
PHPのファイル関数 (,
file_put_contents,
fopen,
fgetsなど) は、基本的にはテキストモード/バイナリモードの区別による改行コードの自動変換は行いません(一部のストリームラッパーやOS固有の挙動を除く)。文字列リテラルや
PHP_EOL定数を使って指定した改行コードがそのままファイルに書き込まれます。
fgets関数は行末を検出する際にCR、LF、CRLFのいずれも認識し、改行コードを含んだ文字列を返します。バイナリモードはファイルオープン時のモード文字列に
b` を付けて使用します。
Shell Script (Bash):
“`bash
!/bin/bash
文字列リテラルでの改行
ダブルクォート内では \n, \r がエスケープシーケンスとして解釈される
単一クォート内では解釈されない
echo “Hello\nWorld” # \n はそのまま表示される
echo -e “Hello\nWorld” # -e オプションで \n が改行として解釈される
エスケープシーケンスを含む文字列を $” 形式で書く
echo $’Hello\nWorld’ # LF
echo $’Hello\rWorld’ # CR
echo $’Hello\r\nWorld’ # CRLF
ファイル書き込み
echo の結果は LF で終わるのが一般的 (環境依存の可能性あり)
echo “Line 1” > output_default.txt
echo “Line 2” >> output_default.txt
LF で書き込みたい場合
echo -e “Line 1\nLine 2\n” > output_lf.txt
CRLF で書き込みたい場合
printf を使うのが確実
printf “Line 1\r\nLine 2\r\n” > output_crlf.txt
ファイル読み込みと改行コードの扱い
cat はファイルをそのまま表示する
echo -e “\nReading files:”
cat output_default.txt
cat output_lf.txt
cat output_crlf.txt # 端末によっては CRLF が LF に解釈されて表示される
改行コードを確認する方法 (cat -vE)
echo -e “\nChecking line endings with cat -vE:”
cat -vE output_default.txt
cat -vE output_lf.txt
cat -vE output_crlf.txt
改行コードを変換する方法 (dos2unix, unix2dos)
CRLF ファイルを作成 (Windows 環境をシミュレート)
printf “DOS Line 1\r\nDOS Line 2\r\n” > dos_file.txt
echo -e “\nOriginal DOS file:”
cat -vE dos_file.txt
CRLF から LF へ変換
dos2unix dos_file.txt
echo -e “\nAfter dos2unix:”
cat -vE dos_file.txt
LF から CRLF へ変換
unix2dos dos_file.txt
echo -e “\nAfter unix2dos:”
cat -vE dos_file.txt
改行コードをプログラムで処理する (例: read)
echo -e “\nReading line by line:”
while IFS= read -r line; do
# read は通常、行末の改行コードを取り除く
echo “Line: \”$line\””
done < output_default.txt
CR が混じっている場合の read の挙動に注意
read は LF を行末と認識し、CR は文字列の一部として残る
printf “Line with CR\r\n” > cr_in_line.txt
echo -e “\nReading line with CR:”
while IFS= read -r line; do
echo “Line: \”$line\”” # Windows で作成した CRLF ファイルを read すると行末に CR が残る
done < cr_in_line.txt
sed を使って改行コードを変換
echo -e “\nConverting with sed:”
CRLF を LF に変換 (行末の CR を削除)
cat output_crlf.txt | sed ‘s/\r$//’ > output_crlf_to_lf_sed.txt
cat -vE output_crlf_to_lf_sed.txt
LF を CRLF に変換 (行末の LF を \r\n に置換) – GNU sed の場合
printf “Line 1\nLine 2\n” | sed ‘:a;N;$!ba;s/\n/\r\n/g’ > output_lf_to_crlf_sed.txt # ファイル全体を一度に
cat -vE output_lf_to_crlf_sed.txt
``
\n
Bashスクリプトでは、文字列リテラル中のや
\rは、
echo -eコマンドを使うか、あるいは
$”という特殊なクォーティング構文を使うことでエスケープシーケンスとして解釈されます。
echoコマンド自体は通常出力の最後にLFを自動で追加します。
printfコマンドはC言語のprintfに近く、自動で改行を追加しないため、改行コードを厳密に指定したい場合に便利です。ファイルを読み込む
readコマンドは、行末のLFを区切りとして扱い、その区切り文字自体は変数には格納しません。Windowsで作成されたCRLFファイルを読むと、各行の末尾にCRが残ってしまうことがあるため注意が必要です。
dos2unixや
unix2dosは最も一般的な変換ツールです。
sed` コマンドも置換機能を使って改行コード変換によく使われます。
PowerShell:
“`powershell
文字列リテラルでの改行
ダブルクォート内では n,
r がエスケープシーケンスとして解釈される
“n" # LF
r” # CR
"
“r
n” # CRLF
シングルクォート内では解釈されない
‘n
rn' # そのまま
nr
n という文字列になる
システム依存の改行コード
“$($Host.UI.RawUI.NewLine)” # ホストアプリケーションの改行コード (通常はCRLF)
“$([System.Environment]::NewLine)” # .NET Framework の Environment.NewLine (通常はCRLF)
$filePathDefault = “.\output_default.txt”
$filePathLF = “.\output_lf.txt”
$filePathCRLF = “.\output_crlf.txt”
$filePathBinary = “.\output_binary.bin”
ファイル書き込み (Out-File)
Out-File はデフォルトでシステム標準の改行コード (WindowsならCRLF) を各行の末尾に追加する
-NoNewline オプションで行末追加を抑制し、自分で改行コードを制御できる
デフォルト (CRLF)
“Line 1” | Out-File -Path $filePathDefault -Encoding UTF8
“Line 2” | Out-File -Path $filePathDefault -Encoding UTF8 -Append # Append で追加
複数の行を一度に書き込む場合は配列を使うと、要素ごとに改行される
@”
Line A
Line B
“@ | Out-File -Path $filePathDefault -Encoding UTF8 -Append
LF で書き込みたい場合
-NoNewline で自動改行を抑制し、自分で `n を追加する
@”
Line 1nLine 2
n” | ForEach-Object { $_ + “`n” } | Out-File -Path $filePathLF -Encoding UTF8 -NoNewline
"@ -split "
CRLF で書き込みたい場合
-NoNewline で自動改行を抑制し、自分で r
n を追加する
@”
Line 1r
nLine 2
“@ -split “r
n” | ForEach-Object { $_ + “r
n” } | Out-File -Path $filePathCRLF -Encoding UTF8 -NoNewline
もしくは、Replace を使う方法がシンプル
(Get-Content $filePathDefault -Raw) -replace “r
n”, “n" | Out-File $filePathLF -Encoding UTF8
n”, “
(Get-Content $filePathDefault -Raw) -replace "r
n” | Out-File $filePathCRLF -Encoding UTF8
ファイル読み込み (Get-Content)
デフォルトでは行ごとに読み込み、改行コードは取り除かれる
“Reading lines:”
Get-Content $filePathDefault | ForEach-Object { “Line: $_” }
ファイル全体を単一の文字列として読み込む (-Raw オプション)。この場合、改行コードも文字列に含まれる。
“Reading raw:”
$contentDefault = Get-Content $filePathDefault -Raw
$contentDefault.Replace(“n","
\n”).Replace(“r","
\r”) # 表示用にエスケープして出力
バイナリモードでの読み書き
System.IO.File::WriteAllBytes や System.IO.File::ReadAllBytes を使用 (.NET の機能)
$binaryData = [byte[]] @(0x41, 0x42, 0x43, 0x0D, 0x0A, 0x44, 0x45, 0x46, 0x0A) # ABC
$binaryContent = System.IO.File::ReadAllBytes($filePathBinary)
“Reading binary:”
$binaryContent | ForEach-Object { “{0:X2} ” -f $_ } # 16進数で表示
echo “” # 改行
``
PowerShellでは、ダブルクォーテーションで囲んだ文字列内でバッククォート () に続く文字(
n,
rなど)がエスケープシーケンスとして解釈されます。
Out-Fileコマンドレットは、デフォルトでシステム標準の改行コードを行末に追加します。
-NoNewlineオプションを使うことでこの挙動を抑制し、自分で改行コードを指定できます。
Get-Contentコマンドレットは、デフォルトで行ごとにファイルを読み込み、改行コードは取り除かれます。
-Rawオプションを付けると、ファイル全体を単一の文字列として読み込み、改行コードも文字列に含まれます。バイナリモードでのファイル操作には、[.NET] の
System.IO.File` クラスの静的メソッドを利用できます。
VBA (Visual Basic for Applications):
“`vba
Sub NewLineExample()
‘ 文字列リテラルでの改行
Dim s1 As String
Dim s2 As String
Dim s3 As String
s1 = "Hello" & vbLf & "World" ' LF (Line Feed)
s2 = "Hello" & vbCr & "World" ' CR (Carriage Return)
s3 = "Hello" & vbCrLf & "World" ' CRLF (Carriage Return + Line Feed)
' VBA にはシステム依存の改行コード定数はない(通常は vbCrLf がシステム標準)
' MsgBox vbCrLf = vbNewLine (Access や Excel の場合)
' vbNewLine は環境によって vbLf または vbCrLf になる
MsgBox "s1 (LF): " & Replace(Replace(s1, vbLf, "\n"), vbCr, "\r")
MsgBox "s2 (CR): " & Replace(Replace(s2, vbLf, "\n"), vbCr, "\r")
MsgBox "s3 (CRLF): " & Replace(Replace(s3, vbLf, "\n"), vbCr, "\r")
MsgBox "vbNewLine: " & Replace(Replace(vbNewLine, vbLf, "\n"), vbCr, "\r")
' ファイル書き込み
Dim fso As Object
Dim ts As Object
Dim filePathDefault As String
Dim filePathLF As String
Dim filePathCRLF As String
Set fso = CreateObject("Scripting.FileSystemObject")
filePathDefault = ThisWorkbook.Path & "\output_default.txt"
filePathLF = ThisWorkbook.Path & "\output_lf.txt"
filePathCRLF = ThisWorkbook.Path & "\output_crlf.txt"
' テキストファイル出力 (通常は CRLF で書き込まれる)
Set ts = fso.CreateTextFile(filePathDefault, True) ' True で上書き
ts.WriteLine "Line 1" ' WriteLine は CRLF を追加
ts.Write "Line 2" & vbCrLf ' vbCrLf を明示的に書き込む
ts.Close
' LF で書き込みたい場合
Set ts = fso.CreateTextFile(filePathLF, True)
ts.Write "Line 1" & vbLf & "Line 2" & vbLf ' vbLf を明示的に書き込む
ts.Close
' CRLF で書き込みたい場合 (WriteLine または vbCrLf)
Set ts = fso.CreateTextFile(filePathCRLF, True)
ts.WriteLine "Line 1"
ts.WriteLine "Line 2"
ts.Close
' ファイル読み込み
Dim contentDefault As String
Dim line As String
' ファイル全体を文字列として読み込み
Set ts = fso.OpenTextFile(filePathDefault, 1) ' 1 = ForReading
contentDefault = ts.ReadAll
ts.Close
MsgBox "Read (default): " & Replace(Replace(contentDefault, vbLf, "\n"), vbCr, "\r")
' 行ごとに読み込み (ReadLine は CRLF, LF, CR を認識する)
Set ts = fso.OpenTextFile(filePathDefault, 1)
MsgBox "Reading line by line:"
Do While Not ts.AtEndOfStream
line = ts.ReadLine ' ReadLine は行末記号を取り除く
MsgBox "Line: " & Replace(Replace(line, vbLf, "\n"), vbCr, "\r")
Loop
ts.Close
' バイナリモードでの読み書き
' VBA の標準的なファイル入出力 (Open, Get, Put) はバイナリに近いが、
' TextFile オブジェクトはテキストモード
' バイナリモードは Open ステートメントと Get/Put を使う
Dim fileNum As Integer
Dim byteData As Byte
Dim binaryFilePath As String
binaryFilePath = ThisWorkbook.Path & "\output_binary.bin"
fileNum = FreeFile ' 未使用のファイル番号を取得
Open binaryFilePath For Binary Access Write As #fileNum
Put #fileNum, , &H41 ' A (0x41)
Put #fileNum, , &H42 ' B (0x42)
Put #fileNum, , &H43 ' C (0x43)
Put #fileNum, , &H0D ' CR (0x0D)
Put #fileNum, , &H0A ' LF (0x0A)
Put #fileNum, , &H44 ' D (0x44)
Put #fileNum, , &H45 ' E (0x45)
Put #fileNum, , &H46 ' F (0x46)
Put #fileNum, , &H0A ' LF (0x0A)
Close #fileNum
fileNum = FreeFile
Open binaryFilePath For Binary Access Read As #fileNum
Dim binaryContent As String
binaryContent = ""
MsgBox "Reading binary:"
Do While Not EOF(fileNum)
Get #fileNum, , byteData
binaryContent = binaryContent & Right("00" & Hex(byteData), 2) & " " ' 16進数で表示
Loop
Close #fileNum
MsgBox binaryContent
Set ts = Nothing
Set fso = Nothing
End Sub
``
vbCrLf
VBAでは、、
vbCr、
vbLfという定数でそれぞれの改行コードを表します。
vbNewLineは環境依存の改行コードですが、Windows環境のVBAでは通常
vbCrLfと同じです。
FileSystemObjectを使った
TextFileオブジェクトの
WriteLineメソッドは、通常システム標準の改行コード(WindowsではCRLF)を自動で追加します。
Writeメソッドは文字列をそのまま書き込みます。
ReadLineメソッドはCR, LF, CRLFのいずれも行末として認識し、改行コードを含まない文字列を返します。バイナリモードでのファイル操作には、
Openステートメントと
Get/
Put` を使用します。
7. ベストプラクティスと注意点
改行コードによる問題を最小限に抑えるためには、以下の点に注意することが重要です。
- チーム開発での改行コード統一: 開発チーム内で使用する改行コードを統一することが最も重要です。どのOSを使用しているメンバーがいても、コードリポジトリにコミットされるファイルはすべて同じ改行コードになっているべきです。一般的には、UNIX系のLFに統一することが多いです。
-
.editorconfig
の活用:.editorconfig
ファイルを使用すると、プロジェクトごとにインデントスタイル、エンコーディング、そして改行コードなどを定義し、チームメンバーや異なるエディタ間での設定の統一を図ることができます。対応しているエディタ(VS Code, Sublime Text, Atom, Notepad++など)を使用していれば、このファイルがあるだけで自動的に設定が適用されます。“`editorconfig
editorconfig.org
root = true
[*]
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true[*.{js,py,java,c,cpp,sh,txt}]
LF (Unix/Linux/macOS) に統一する場合
end_of_line = lf
[*.{bat,cmd,ps1}]
Windows のスクリプトなど、どうしても CRLF が必要な場合は個別に設定
end_of_line = crlf
``
core.autocrlf
* **Git の設定の理解と適切な利用:** Gitは改行コードの自動変換機能を持っています。
core.autocrlf = true
*(Windows推奨): チェックアウト時にLFをCRLFに変換し、コミット時にCRLFをLFに変換します。Windowsユーザーがリポジトリ内でLFとして扱われるようにするための設定です。
core.autocrlf = input
*(Unix/macOS推奨): コミット時にCRLFをLFに変換しますが、チェックアウト時は変換しません。CRLFが誤ってコミットされるのを防ぎます。
core.autocrlf = false`: 自動変換を行いません。改行コードの扱いはすべてユーザーに任されます。
*チームで改行コードを統一し、
.editorconfig
でend_of_line = lf
を設定している場合、Windowsユーザーはcore.autocrlf = true
を、Unix系ユーザーはcore.autocrlf = input
またはfalse
を設定するのが推奨されます(false
の方が予測可能ですが、意図しないCRLF混入のリスクは上がります)。最も安全なのは、チーム全員がfalse
に設定し、.editorconfig
やエディタ設定、Gitの.gitattributes
ファイルで改行コードを厳密に管理する方法です。 -
.gitattributes
ファイルの活用:.gitattributes
ファイルを使うと、ファイルの種類ごとに改行コードの扱いを詳細に制御できます。例えば、すべてのテキストファイルをLFとして扱うには* text=auto eol=lf
のように記述します。これはcore.autocrlf
より優先されます。“`gitattributes
すべてのテキストファイルを自動判別し、チェックアウト時は OS 標準、コミット時は LF に変換
- text=auto
特定の拡張子のファイルを常に LF にする
.sh text eol=lf
.py text eol=lf特定の拡張子のファイルを常に CRLF にする (Windows 用スクリプトなど)
*.bat text eol=crlf
バイナリファイルとして扱い、変換を一切行わない (画像ファイルなど)
*.png binary
``
dos2unix
* **クロスプラットフォーム開発での考慮事項:** 複数のOS環境で動作するソフトウェアを開発する場合、ファイル入出力の際には改行コードの扱いに特に注意が必要です。OS標準の改行コードに依存するか、常にLFやCRLFなど特定の改行コードを使用するかを設計段階で決め、コード内で一貫して扱うようにします。多くの場合は、内部処理ではLFを使用し、ファイルへの書き出し時のみOS標準に変換する、あるいは常にLFで書き出す、といった戦略を取ります。
* **テキストファイルとバイナリファイルの明確な区別:** ファイルの種類によって、改行コードの扱い方は異なります。テキストファイルは改行コードが意味を持ちますが、バイナリファイル(画像、実行ファイルなど)ではバイト列としての意味しかありません。プログラミング言語のファイル入出力でも、テキストモードとバイナリモードを適切に使い分けることが重要です。
* **シェルスクリプトや設定ファイルでのCRLF問題への対処法:** Windowsで作成したシェルスクリプトなどをLinuxで実行する際にCRLFが原因でエラーになる場合は、コマンドなどでLFに変換してから実行するのが最も手軽な解決策です。または、スクリプト内で
sed ‘s/\r$//’` のようにCRを取り除く処理を挟むこともあります。
8. まとめ
改行コードは、普段は意識されない目に見えない文字ですが、テキストファイルの構造を定義し、人間にとって読みやすい形式にするための重要な制御文字です。
- 主要な改行コードには、LF (
\n
)、CR (\r
)、CRLF (\r\n
) の3種類があります。 - LF はUNIX、Linux、macOSなどで、CRLF はWindowsで標準的に使用されています。CR単体はClassic Mac OSで使われていました。
- 異なるOSや環境間でファイルをやり取りする際に、改行コードの違いによる表示崩れやスクリプトの実行エラーといった互換性の問題が発生することがあります。
- テキストエディタやコマンドラインツール(
cat -vE
,od -c
,nkf
,dos2unix
/unix2dos
など)を使って、ファイルの改行コードを確認したり、目的の改行コードに変換したりすることができます。 - プログラミング言語では、文字列リテラルで
\n
や\r
を使って改行コードを表現し、ファイル入出力においてはテキストモードとバイナリモードの区別や、OS標準の改行コード(Pythonのos.linesep
, JavaのSystem.lineSeparator
, C#のEnvironment.NewLine
など)を考慮する必要があります。多くの言語のテキストモードでは、OS標準の改行コードに合わせて自動変換が行われることがあります。 - チーム開発においては、
.editorconfig
や.gitattributes
、Gitのcore.autocrlf
設定などを活用して、改行コードを統一することが非常に重要です。
改行コードに関する知識は、コンピュータでテキストデータを扱う上での基本であり、特に開発者にとっては避けて通れない課題です。この記事を通じて、改行コードの種類、その重要性、そして様々な環境や言語での扱い方について深く理解していただけたなら幸いです。目に見えない小さなコードですが、適切に理解し、管理することで、多くの互換性問題を未然に防ぎ、よりスムーズな開発やデータ処理が可能になります。