PDFファイルはバイナリデータも含みますが、基本的にはテキストファイルです。
改行コードが\r、\n、\r\nの3種類あり得るため、実際にPDFファイルへアクセスする前に改行コードを処理できるファイル読み込みクラスを作成します。
今回はVisual Studio 2012を利用しました。
「ファイルメニュー」の「新規作成」にある「プロジェクトの作成」を選択し、新しいプロジェクトを作成します。
テンプレートは「Visual C#」の「Windows」にある「Windowsフォームアプリケーション」を採用し、プロジェクト名は「Pdf2Pdf」としました。
次に「プロジェクト」メニューかあら「クラスの追加」を選択し、「PDFRawReader.cs」というクラスを追加し、中身を以下のようにして終わり。
今回はクラスを作っただけなので動作は一切ありません。
using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Pdf2Pdf { class PDFRawReader : BinaryReader { public PDFRawReader(Stream strm) : base(strm) { } public char cbCommentChar { get { return _cbCommentChar; } set { _cbCommentChar = value; } } char _cbCommentChar = '%'; /// <summary> /// 1行ずつ読み込む /// bSkipCommentLine == trueならコメント行(%から始まる行)は読み取らない /// </summary> public string ReadLine(bool bSkipCommentLine) { return ReadLine(Encoding.ASCII, bSkipCommentLine); } /// <summary> /// 1行ずつ読み込む /// bSkipCommentLine == trueならコメント行(%から始まる行)は読み取らない /// </summary> public string ReadLine(Encoding enc, bool bSkipCommentLine) { do { byte tmp; byte[] data = new byte[0]; int n = 0; try { while (true) { //改行コードチェック(\r、\r\n、\nの3通りあり得る) tmp = ReadByte(); if (tmp == 0x0d) //\rなら、\r\nか\rかをチェック { tmp = ReadByte(); if (tmp == 0x0a) //\r\nだった break; //\r\nではなく、\rだったので一文字戻してから抜ける BaseStream.Seek(-1, SeekOrigin.Current); break; } if (tmp == 0x0a) break; Array.Resize(ref data, data.Length + 1); data[n] = tmp; n++; } } catch (Exception) { } string ret = enc.GetString(data); if (bSkipCommentLine == false || string.IsNullOrEmpty(ret) || ret[0] != _cbCommentChar) return ret; } while (true); } /// <summary> /// データを参照する(シーク位置は変えない) /// </summary> byte ReferByte(int nOffset) { byte ret; long current = BaseStream.Position; BaseStream.Seek(nOffset, SeekOrigin.Current); ret = ReadByte(); BaseStream.Seek(current, SeekOrigin.Begin); return ret; } public string ReadBackLine(bool bSkipCommentLine) { return ReadBackLine(Encoding.ASCII, bSkipCommentLine); } /// <summary> /// 現在のシーク位置に対して前の1行を読み込む /// ※どんどんファイル先頭側へシークしていく /// /// bSkipCommentLine == trueならコメント行(%から始まる行)は読み取らない /// </summary> public string ReadBackLine(Encoding enc, bool bSkipCommentLine) { do { byte tmp; int nBreakLine = 0; int nReferPos = 0; List<byte> listData = new List<byte>(); try { //直前の改行コードは無視する { nReferPos--; tmp = ReferByte(nReferPos); //改行コードチェック(\r(0x0d)、\r\n(0x0d0a)、\n(0x0a)の3通りあり得る) { if (tmp == 0x0a) //\nなら、\r\nか\nかをチェック { byte tmp2 = ReferByte(nReferPos - 1); if (tmp2 == 0x0d) { //\r\nだった nReferPos--; } else { //\r\nではなく、\nだった } } else if (tmp == 0x0d) { //\rだった } } } while (nBreakLine == 0) { nReferPos--; tmp = ReferByte(nReferPos); //改行コードチェック(\r(0x0d)、\r\n(0x0d0a)、\n(0x0a)の3通りあり得る) { if (tmp == 0x0a) //\nなら、\r\nか\nかをチェック { byte tmp2 = ReferByte(nReferPos - 1); if (tmp2 == 0x0d) { //\r\nだった nBreakLine++; continue; } else { //\r\nではなく、\nだった nBreakLine++; continue; } } else if (tmp == 0x0d) { //\rだった nBreakLine++; continue; } } listData.Insert(0, tmp); } } catch (Exception) { } BaseStream.Seek(nReferPos + 1, SeekOrigin.Current); string ret = enc.GetString(listData.ToArray()); if (bSkipCommentLine == false || string.IsNullOrEmpty(ret) || ret[0] != _cbCommentChar) return ret; if (BaseStream.Position == 0) return ret; } while (true); } } }