【C#】テキストファイルの一部を,StreamWriter無しで書き換えたい時
関連記事
【#CSharp】制御系が動き出したべ 【2025年02月20日(木)】
【#CSharp】ひっさしぶりにガッツリなC#案件をやっているぞー 【2025年02月19日(水)】
- 今週もひたすらモノ書き #JAVA 祭りがまだまだ続く そろそろC#を書かせろー 【2024年12月04日(水)】
- 【#CSHARP】ソリューション内でサービス,Winformアプリを混在で作成させ,バイナリ出力先を同じにするとサービスが起動しない 【2024年02月08日(木)】
- 【#PHP】謎な #Laravel 案件 引き渡したじ 【2024年01月11日(木)】
バイナリデータをテキスト化して出力,処理最終段で
ヘッダとして利用している先頭部分に,このファイルのデータブロック総行数を書き込まないといけなくなったもんで
まぁ,行数が数1000行ぐらいなら,StreamReader,StreamWriterあたりを使って
再読み込み~書き換え~別ファイルとして保存,って手がお手軽じゃけど...
対象は最大数10万行に達する可能性も
たった1箇所の書き換えに,このやり方はオーバーヘッドが洒落にならん!
ってことで.ちょいと書き起こしてみたが,これがテゲ面倒じゃった
まずは,書き換え対象のファイル
aaaa
iiii
1くまさんだぁ~
マキマキらぶ
hogehoge
%TEST%
まだまだ続くヨォ~
空行も挟んだ
エヴァンゲリオン
もういいじゃろ?
これで終わり
‘%TEST%'(6文字分)って文字を置き換えます
して,ソース
FileStreamを使って,バイナリモードでテキストファイルを読み込み
改行を検出したら,バイナリを文字列化
‘%TEST%’を’CHG ‘に置き換えます.置き換え後の文字byte数は,置き換える前のバイト数と同じにしておかないと,トラブりまする
んで,先頭からのバイト数を加算しておき,置き換え処理を行うときは,
FileStream.Seek()で,ファイルポインタを戻して,バイナリモードで書き換えて,処理完了,って流れです
ちとソースが長いですが,参考にドゾー
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace filereplace
{
public partial class Form1 : Form
{
private const string REPLACESTR = “%TEST%”;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
System.IO.FileStream fs = System.IO.File.Open( “z:\\replacetest.txt”,
System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite );
byte[] readbuf = new byte[65536];
byte[] writebuf = null;
int readbufoffset = 0;
long fileoffset = 0;
bool filejobfl = true;
while (fs.Position < fs.Length)
{
if ((readbufoffset + 10) >= readbuf.Length) //改行コードを見つけられずにバッファオーバーした場合
{
//なんらかのエラー処理
break;
}
int readresult = fs.Read(readbuf, readbufoffset, 10);
if (readresult == 0)
{
break;
}
else
{
readbufoffset += readresult;
}
bool LoopFL = true;
while(LoopFL == true)
{
int cridx = 0;
bool crfl = CheckCR(readbuf, out cridx);
if ( crfl == true)
{
byte[] tmpbuf = new byte[cridx+2];
Array.Copy(readbuf, tmpbuf, cridx+2);
string st = Encoding.GetEncoding(“shift_jis”).GetString(tmpbuf);
MoveAry(readbuf, cridx+2); //前に詰める
readbufoffset -= cridx+2; //バッファの最終位置を調整
if (st.IndexOf(REPLACESTR) >= 0)
{
st.Replace(REPLACESTR, “CHG “); //%TEST%をCHG に置き換え
fs.Seek(fileoffset, System.IO.SeekOrigin.Begin);
writebuf = Encoding.GetEncoding(“shift_jis”).GetBytes(“CHG “);
fs.Write(writebuf, 0, writebuf.Length);
filejobfl = false;
LoopFL = false;
break;
}
byte[] dmybuf = Encoding.GetEncoding(“shift_jis”).GetBytes(st); //先頭からのbyte長を加算
fileoffset += dmybuf.Length;
}
else
{
LoopFL = false;
}
}
if (filejobfl == false)
{
break;
}
}
fs.Close();
}
//改行コードの発見
private bool CheckCR(byte[] buf, out int Idx)
{
Idx = -1;
for(int i = 0; i < buf.Length; i++)
{
if ((i + 1) >= buf.Length)
{
return false;
}
if ((buf[i] == ‘\r’) && (buf[i+1] == ‘\n’))
{
Idx = i;
return true;
}
}
return false;
}
//配列を前に詰める
private void MoveAry(byte[] buf, int mvCount)
{
for(int i =0; i < buf.Length; i++)
{
if ((i + mvCount) >= buf.Length)
{
break;
}
if (buf[i + mvCount] == ‘\0’)
{
for( int j = i; j < buf.Length; j++)
{
buf[j] = (byte)'\0';
}
break;
}
buf[i] = buf[i + mvCount];
}
}
}
}
[/csharp]
コメント
宮崎ー台湾 国際定期便が週2往復に増便へ 来月30日から(25/2/15)
『にっぽん縦断 こころ旅』4月から田中美佐子が新たな旅人に 火野正平さんが14年間担当
オリックス・バファローズのキャンプ見学に行ってきた,昨日(爆(25/2/9)
【大雪】9日も降り続く見込み 交通影響に警戒 雪崩など注意を(25/2/9)
日産、ホンダとの統合合意撤回へ(25/2/5)
【特殊詐欺:トクリュウ】+1-844-173-3313から電話キター 特殊詐欺だぁ~~これはアカンヤツ
備蓄米放出へ準備、流通不足で初 政府、買い戻し条件に売り出し