【问题标题】:Stream read error流读取错误
【发布时间】:2011-03-15 21:34:19
【问题描述】:

我在负载过重的情况下收到此错误消息。这是我的错误日志中的代码摘要和消息。 我尝试了我能想到的一切。任何建议将不胜感激。

Procedure tCacheInMemory.StreamValue(Name: String; IgnoreCase: Boolean; Var Stream:     TStringStream);
Var
  i: Integer;
Begin
  i := 0;
  Try
    If Not active Then
      exit;
    arrayLock.BeginRead;
    Try
      i := Search(Name);
      If i > -1 Then Begin
        If fItems[i].value = Nil Then
          exit;
        fItems[i].value.Position := 0;
        Stream.Position := 0;
        Stream.CopyFrom(fItems[i].value, fItems[i].value.Size);
      End;
    Finally
      arrayLock.EndRead;
    End;
  Except { ...execution jumps to here }
    On E: Exception Do Begin
      x.xLogError('LogErrorCacheInMemory.txt', 'StreamValue:' + E.Message + ' ItemsCount:' + IntToStr( High(fItems)) + 'Memory:' + IntToStr(x.GetMemoryInfoMemory) + endLn + 'StreamSize : ' + IntToStr(fItems[i].value.Size) + ' i=' + IntToStr(i) + 'Name: ' + Name);
      Clear;
    End
  End;
End;

日志条目:

 3/10/2011 10:52:59 AM: StreamValue:Stream read error ItemsCount:7562 Memory:240816
   StreamSize : 43 i=7506 Name: \\xxxxxxxx\WebRoot\\images\1x1.gif
3/10/2011 12:39:14 PM: StreamValue:Stream read error ItemsCount:10172 Memory:345808
   StreamSize : 849 i=10108 Name: \\xxxxxxxx\WebRoot\\css\screen.add.css
3/10/2011 3:45:29 PM: StreamValue:Stream read error ItemsCount:11200 Memory:425464
   StreamSize : 3743 i=11198 Name: \\xxxxxxxx\WebRoot\\JS\ArtWeb.js

附:

arrayLock: TMultiReadExclusiveWriteSynchronizer;
 fItems: Array Of rCache;
Type
  rCache = Record
    Name: String;
    value: TStringStream;
    expired: TDateTime;
  End;

以及调用函数:

Function tCacheInMemory.CacheCheck(cName: String; Out BlobStream: TStringStream):   Boolean;
Begin
Result := False;
   If Not IfUseCache Then
      exit;
    BlobStream.SetSize(0);
    BlobStream.Size := 0;
    StreamValue(trim(cName), True, BlobStream);
    If BlobStream.Size > 0 Then
    Result := True;
End;

`

【问题讨论】:

  • 您确定创建了“Stream”吗?我没有看到任何代码检查。您为 Items[].Value 执行此操作。 Search() 还有什么作用?它是否与流交互?
  • 您标记了执行跳转的位置 - 它从哪里跳转到达那里?
  • 流已创建。您可以在错误日志中看到 StreamSize 和大小(以字节为单位)。 Items.Value 是一个 TStringStream。搜索是一种自定义的二分搜索。它不交互。只返回索引。
  • StreamSize 在您的日志中指的是 Items[].value 而不是 Stream 变量。您的代码中有多个流变量。
  • 与错误无关的代码有两点:(1)您不应将Stream 参数作为var 传递。按值传递它,并将其声明的类型更改为 TStream,允许调用者传递任何类型的流而不是完全 TStringStream 对象。 (2) 如果您在缓存中找到的流比目标流的当前内容,那么目标流最后会包含垃圾。复制后需要截断。

标签: delphi delphi-2010


【解决方案1】:

您没有使用正确的锁定。您正在获取缓存条目数组的读取 锁,但是一旦找到所需的项目,您就修改它。首先,您显式通过分配它的Position 属性来修改它,然后隐式通过读取它来修改它,这又修改了它的Position 属性。当其他代码尝试从同一个缓存项中读取时,您将受到干扰。如果源流的Position 属性在目标流计算可用字节数和它实际请求读取这些字节的时间之间发生变化,则会出现流读取错误。

我有一些与此相关的建议:

  • 首先不要将流用作存储设备。您显然持有文件的内容。您不会更改这些,因此您不需要为进行顺序更改而设计的数据结构。相反,只需将数据存储在简单的字节数组中:TBytes。 (另外,使用TStringStream 尤其会导致混淆这些字符串的编码是否重要。一个简单的文件缓存根本不应该关心字符串编码。如果您必须使用流,使用与内容无关的类,例如 TMemoryStream。)
  • 不要平息没有实际处理的异常。在这段代码中,您将捕获所有异常类型、记录一些信息、清除缓存,然后一切正常。但是您还没有解决触发异常的问题,所以一切都正常。由于您并没有真正处理异常,因此您需要确保它传播给调用者。拨打raise后拨打Clear。 (当您记录异常时,请确保记录异常的 ClassName 值及其消息。)

【讨论】:

  • 感谢罗布。你拯救了我的一天。 TBytes 听起来很有希望。关于错误处理 - 这是设计使然。如果发生不好的事情,结果将是一个空字符串,它将触发从其他源(文件、数据库等)刷新此资源。我不应该打电话给Clear,也不会(在我修复它之后)。我会按照你的建议记录Class Name。再次感谢你。尤里。
  • 您正在处理 EReadError、EAccessViolation、EOutOfMemory 和 EPrinterOnFire,就好像它们都是平等的,并且都可以通过简单的日志消息来解决。具体来说,您希望抓住什么?该代码中不应出现任何错误,因此如果确实出现问题,您需要立即了解它,因为您的程序中存在错误。如果程序错误与普通缓存未命中无法区分,那么您无需读取指向确切错误的堆栈跟踪,而是收集细微数据损坏的报告。
【解决方案2】:

看起来外部的东西正在阻止您的流文件。

您可以尝试使用Process Monitor 来查看是什么阻止了它。

您可以尝试的另一件事是以读-拒绝-写模式打开流(请告诉我们您是如何打开流的)。

类似这样的:

Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite) ;

编辑 1: 忽略删除线部分:您正在使用 TStringStream。
我会保留答案,以防万一有人在使用 TFileStream 时遇到这种错误。

编辑 2: Yuriy 发布了这个有趣的附录,但我不确定它是否会起作用,因为 BlobStream 没有初始化,就像 Robert Love 被怀疑一样:

Function TCacheInMemory.CacheCheck(cName: String; Out BlobStream: TStringStream): Boolean; 
Begin 
  Result := False; 
  Try 
    If Not IfUseCache Then 
      exit; 
    BlobStream.SetSize(0);  
    BlobStream.Size := 0;  
    StreamValue(trim(cName), True, BlobStream);  
    If BlobStream.Size > 0 Then  
      Result := True;  
  Except  
    On E: Exception Do  
    Begin  
      x.xLogError('LogErrorCacheInMemory.txt', 'CheckCacheOutStream:' + E.Message + ' ItemsCount:' + IntToStr( High(fItems)) + 'Memory:' + IntToStr(x.GetMemoryInfoMemory));  
    End;  
  End;  
End; 

--杰罗恩

【讨论】:

  • @jeroen 别担心,删除后您将获得 2 分!
  • @David:啊,所以删除了这样的工作。很高兴知道,但我宁愿保留这部分知识,以防其他人从中受益。
  • @Yuri:你应该把这部分作为你的问题;同时,我会将其添加到我的答案中(并感谢您),如果您将其添加到您的问题中,我会将其从我的答案中删除。
  • @Jeroen 为什么将此代码添加到您的答案中?它肯定属于问题吗?
  • @David 让 Yuriy 有机会更新他的问题。这让他有机会在这里获得一些经验(他是一个新用户)。
猜你喜欢
  • 1970-01-01
  • 2017-03-13
  • 2012-10-06
  • 2015-07-23
  • 1970-01-01
  • 2013-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多