微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

文本文件内容的文件大小和字符串字节长度的区别?

如何解决文本文件内容的文件大小和字符串字节长度的区别?

我正在尝试用 Tcl 编写一个非常小的特定于应用程序的本地服务器,但不明白确定 Content-length 的正确方法。我读到它是字节或八位字节的十进制数。

在下面的代码中,[file size "index.html"] 返回正确的长度,以便浏览器读取/加载所有内容;但是 [string bytelength $html] 太小,浏览器没有读到最后。

为什么会这样,有没有更好的方法?谢谢。

if { $op eq "GET" } {
  if { $arg eq "/" } {
    set fp [open "index.html" r]
    set html [read $fp]
    set resp "HTTP/1.1 200 OK\n"
    append resp "Connection: Keep-Alive\n"
    append resp "Content-Type: text/html; charset: utf-8\n"
    append resp "Content-length: [file size "index.html"]\n\n"
    #append resp "Content-length: [string bytelength $html]\n\n"
    append resp $html
    puts stdout $resp
    puts $so $resp
    close $fp
    unset html resp
  }
  # Remainder of if $arg
}

解决方法

file size 的结果是文件在磁盘上占用的字节数,正是操作系统报告的字节数。 (这也是您打开文件并seek编辑到最后的偏移量。)

如果您以二进制模式读取文件,您读取的内容的 string length 将与 file size 相同。当以(默认)文本模式读取文件时,它是不同的,因为它取决于读取文件的编码; UTF-8 等编码可以使用多个字节来描述一个字符,string length 报告字符串中的字符数。

string bytelength 命令报告数据使用 Tcl 的内部编码(与 UTF-8 非常相似,但不完全相同;有特定的非规范化)编码时使用的字节数。该编码通常不会暴露给外部世界,并且只有 C 扩展才真正感兴趣。当然,无论如何,这些 C 扩展可以轻松地为自己获取字符串的长度:它是由 Tcl_GetStringFromObj() 生成的(作为 OUT 参数,因为字符串本身就是返回值)所以 string bytelength 不是很有用。确实,我只发现了 (1) 对其的合法用途,如果能更好地与该扩展程序集成工作,就会摆脱它。 >

string bytelength 报告的值不是值当前使用的存储量,而只是(与静态差异密切相关)使用的存储量标准的“字符串”解释。如果该值还有任何其他(“内部”)表示,这是常见的(数字、二进制数据、真正的 unicode 数据、列表、字典、命令名称、通道处理程序、可执行代码,所有这些都可能有额外的表示数据)那么这被计算在内。

在您的情况下,您想以 二进制 模式打开文件并使用它。也这样做:

set filename "index.html"
set fp [open $filename rb];   # NB: rb — b is for BINARY; this is important
set size [file size $filename]

# HTTP spec says headers are ISO 8859-1 and CRLF-separated
fconfigure $so -encoding iso8859-1 -translation crlf
set headers ""
append headers "HTTP/1.1 200 OK\n"
append headers "Connection: Keep-Alive\n"
# Detecting the content type of a file is its own chunk of complexity
append headers "Content-Type: text/html; charset: utf-8\n"
append headers "Content-length: $size\n"
puts stdout $headers
puts $so $headers

# Ship the data in binary mode; fcopy is VERY efficient
fconfigure $so -translation binary
fcopy $fp $so -size $size
close $fp

由于使用了混合编码,将 HTTP 消息写入控制台有点混乱;编写文件主体通常不是一个好主意。但是为了调试,你会这样做:

set data [read $fp]
puts stdout $data
# Additional -nonewline to not add a line terminator
puts -nonewline $so $data

然而,将二进制数据从一个地方移动到另一个地方时,fcopy 命令(在较新的 Tcl 中也称为 chan copy 作为命令系统化工作的一部分)要高效得多。我们可以显着提高效率的唯一方法是将副本移动到操作系统内核中。


tl;dr:您不想使用 string bytelength。它所做的事情显然没有用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。