第02回 ファイルから行単位で読み込む

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);
		}
	}
}

プロジェクトファイルをダウンロード


カテゴリー「PDFを処理する(C#)」 のエントリー