如何解决文本文件内容的文件大小和字符串字节长度的区别?
我正在尝试用 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] 举报,一经查实,本站将立刻删除。