(或者,当被 1023 整除时(见下面的更新 3))
我正在寻找一个错误,当包含要提取的数据的文件的大小可以被 1024 整除时,就会出现一个错误。在这种情况下,提取似乎一直工作到完成,但最后却失败了。
考虑到在这种情况下可能会发生一些奇怪的事情(当有一个文件的大小是 1024 的倍数时),我在代码中搜索了对“1024”的任何引用,但没有具体提到“1024”的实时代码。”
我确实在获取代码中发现了一件我认为看起来很奇怪的东西,即:
connFrmSitesData.Dispose();
connFrmSitesData = null;
将表单设置为 null 是否可能导致问题?有什么理由让它存在吗?
更新
我发现这段代码让我想知道:
string theMessage = new string( '\x00', 1023 );
...如果它可能与问题无关。
更新 2
现在我看到那个字符串 (theMessage)* 甚至没有被使用;我能够将其注释掉(在所有三个类似声明且此后未使用的地方)。
那么为什么在这段代码中有:
bool retVal = false;
string theMessage = new string( '\x00', 1023 ); // fill 1023 bytes with nulls
. . .
if( retVal = Util.NetSendCommand( rc.command ) )
...“retVal”是变灰的变量(我假设是 Resharper),而“theMessage”没有变灰?
还有一个“正常”** theMessage 声明为类私有:
私人字符串 theMessage;
** “正常”,因为它没有用重载的构造函数实例化。
更新 3
我可能已经找到了问题区域(实际上在不同的项目中 - 项目调用的 .DLL)。
此代码是可疑的,因为 MAXREAD = 1023。
任何人都可以看到这会导致精确大小的文件失败的任何问题吗?例如,如果先前的 Read 已获得所有内容,对 bReader.Read() 的调用会失败吗?
还是这里的某个地方潜伏着其他问题?
BinaryReader bReader = null;
. . .
bReader = new BinaryReader( theN_Stream );
. . .
fsWriteText = new FileStream( destFPath, FileMode.Create, FileAccess.Write );
. . .
bWriter = new BinaryWriter( fsWriteText );
. . .
/* --------------------------------------- *
* Incoming message may be larger than
* the buffer size.
* --------------------------------------- */
int index = 0;
int indexLast = 0;
int next2Read = MAXREAD;
try
{
// keep doing this until no data available on the stream, ...
do
{
next2Read = MAXREAD; //1023
longString = "";
Array.Clear( readbuffer, 0, MAXREAD );
numberOfBytesRead = bReader.Read( readbuffer, 0, next2Read );
indexLast = index;
realTotBytesRead += numberOfBytesRead;
index += numberOfBytesRead;
nBytes += numberOfBytesRead;
xferProgress = nBytes.ToString() + "|" + fsize.ToString();
OnProgressChanged(xferProgress);
if( bWriter != null )
{
if( bWriter.BaseStream.CanWrite )
{
bWriter.Write( readbuffer, 0, numberOfBytesRead );
}
}
if( index >= fsize )
{
haveFinishedRead = true;
break;
}
if( !theN_Stream.CanRead )
{
break;
}
} while( index < fsize );
更新 4
在试图解决这个问题的过程中,我编译了(不是双关语)以下注释。
// readbuffer 是一个字节数组。// bReader 是一个二进制阅读器
“索引”从 0 开始,分配读取的字节数(1023 或剩余/最后一位),稍后针对文件大小进行测试 - 如果等于或更大,则退出循环。
“indexLast”从 0 开始,首先分配 index 的值(第一次通过循环时为 0,之后为 1023 或余数/最后一位),但它从未被引用,因此可以将其注释掉。
"next2Read" 最初分配为 MAXREAD,即 1023。它在这一行中使用:
numberOfBytesRead = bReader.Read( readbuffer, 0, next2Read );
...但此后未引用,因此可以将其删除,并且上面的行更改为:
numberOfBytesRead = bReader.Read( readbuffer, 0, MAXREAD);
"longString" 被初始化为一个空字符串,但是没有在任何地方被引用;但是,由于它是一个全局变量,也许其他地方需要这个值?
"numberOfBytesRead" 被分配了 bReader 的 Read() 方法的返回值。然后将其分配给“index”和“nBytes”。然后在调用 bWriter.Write() 时将其用作“要写入的字节数”。
与“longString”一样,“realTotBytesRead”被分配给此方法,然后在此方法中不被引用,但由于它是一个全局变量,它可以在其他地方使用...
“nBytes”在“numberOfBytesRead”中被赋值,然后用于进度条。似乎可以使用“numberOfBytesRead”并切断中间人,但我猜“nBytes”并没有伤害任何东西(除了让我的头骨不会塌陷的糊状灰色东西)......
“fsize”用于条件分支。它最初设置为 0,然后这样设置:
fsize = (int)Int32.Parse( fFileSz );
“fFileSz”是一个公共静态字符串,它保存文件大小(在别处设置)。
“theN_Stream”是一个网络流。
在调试计算机程序时,您有点像侦探,但不是在黑暗的小巷里追捕坏人并揭露罪犯,而是在吸食行为不端的人。这种侦探工作比另一种更安全——更久坐不动,也更稳重——但是你从备用鞋皮中获得的收益和节省的人寿保险费,你会在突触破裂和过度劳累的脑细胞中损失惨重,WAY超越“云”;在你做/不做的每一件事上总是有一个权衡。
更新 5
我现在预计问题出在其他地方,因为无论文件大小小于、等于还是大于 MAXREAD (1023),此代码似乎都可以工作。伪代码:
//文件大小 < MAXREAD:
if filesize == 1022:
numberOfBytesRead == 1022
index == 1022;
//....breaks out (as it should, it's done), because index == fsize
//文件大小 == MAXREAD: //1023
if filesize == 1023:
numberOfBytesRead == 1023
index == 1023;
//breaks out (as it should, it's done), because index == fsize
//文件大小> MAXREAD:
if filesize == 1024:
numberOfBytesRead == 1023
index == 1023;
...continues to loop again:
numberOfBytesRead == 1
index == 1024;
//breaks out (as it should, it's done), because index == fsize
// 对于任何文件大小 > MAXREAD 都应该相同
更新 6
已找到“神奇数字” - 处理 190KB 大小的文件时应用程序崩溃。显示获取过程的进度条比冻结 - 永远并且在每次文件大小正好如此的情况下;否则很好(如果文件大小小于或大于 190KB,则可以正常工作)。
更新 7
我意识到这是一个糟糕的修复,但遗留代码是如此复杂,[故意?]混淆,和花招——DLL调用exe,反之亦然,多个后台线程触发和停止,闪烁和像来自疯人院的闪光灯一样闪烁——我以这种方式强行临时修复,更改了以下代码:
if( processMessage )
{
Util.ProcessServerResponse( theMessage.Trim( uDelims.ToCharArray() ) );
}
...对此:
if ( processMessage )
{
string valToPass = theMessage.Trim(uDelims.ToCharArray());
if (valToPass.IndexOf("190980") > 0)
{
valToPass = valToPass.Replace("190980", "190978");
}
Util.ProcessServerResponse( valToPass );
}
// 注意: 1) 出于某种原因,当文件大小为 190980 时,DLL 中会出现无限循环,其中“索引”(已读取的字节数)仍然小于表示要读取的总字节数的值 - 所有其他文件大小或所有其他文件大小的很大一部分,它工作正常...... 2)我不能使用 string.Contains() 来查找“190980”,只是因为它在 .NET 1.1 中不可用