ASP TextStream
TextStream 的读写方法、逐行处理、编码与位置控制。
属性与方法
| Member | Purpose |
|---|---|
Read(n) | 按字符读 |
ReadLine | 不含换行符 |
ReadAll | 整个文件 |
Skip(n) | 跳过 n 个字符 |
SkipLine | |
Write(s) | 不换行 |
WriteLine(s) | 自动加换行 |
WriteBlankLines(n) | n 个换行 |
AtEndOfStream | 读到末尾为 True |
Line / Column | 当前行列 |
逐行读取
<%
Dim fso, ts, line, n
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile(Server.MapPath("/data/users.txt"), 1)
n = 0
Do While Not ts.AtEndOfStream
line = ts.ReadLine
n = n + 1
Response.Write n & ": " & Server.HTMLEncode(line) & "<br>"
Loop
ts.Close
Set ts = Nothing
Set fso = Nothing
%>1: Ada,ada@example.com
2: Bob,bob@example.com
3: Cy,cy@example.comUse Do While Not ts.AtEndOfStream rather than a fixed count: the number of lines is unknown, and a hardcoded loop either truncates or reads empty lines.
逐行写入
<%
Dim rows, i
rows = Array("Ada,ada@example.com", "Bob,bob@example.com")
Set ts = fso.CreateTextFile(Server.MapPath("/data/users.txt"), True)
For i = 0 To UBound(rows)
ts.WriteLine rows(i)
Next
ts.Close
%>The second argument True means overwrite if present. With False an existing file raises an error — an easy omission that produces a "file already exists" runtime error.
解析 CSV
<%
Dim parts
Do While Not ts.AtEndOfStream
parts = Split(ts.ReadLine, ",")
If UBound(parts) >= 1 Then
Response.Write "<tr><td>" & Server.HTMLEncode(parts(0)) & _
"</td><td>" & Server.HTMLEncode(parts(1)) & "</td></tr>"
End If
Loop
%>Split handles simple CSV but breaks on fields containing commas or quoted escapes. Real CSV needs a quote-aware parser; Split splits "Ada, Jr." into two fields.
编码
<%
' 默认按 ASCII 读写,中文会变问号
Set ts = fso.CreateTextFile(path, True, True) ' 第三参数 True = Unicode(UTF-16)
Set ts = fso.OpenTextFile(path, 1, False, -1) ' 第四参数 -1 = Unicode
Set ts = fso.OpenTextFile(path, 1, False, 0) ' 0 = ASCII(默认)
Set ts = fso.OpenTextFile(path, 1, False, -2) ' -2 = 系统默认编码
%>The encoding argument only offers ASCII, Unicode (UTF-16) and system default — no UTF-8. For UTF-8 files use ADODB.Stream with Charset = "utf-8".
<%
Dim st
Set st = Server.CreateObject("ADODB.Stream")
st.Type = 2 ' 文本
st.Charset = "utf-8"
st.Open
st.LoadFromFile Server.MapPath("/data/utf8.txt")
Response.Write st.ReadText
st.Close
Set st = Nothing
%>TextStream suits small files. ReadAll on a tens-of-MB log loads it all into memory and spikes the IIS worker. Use ADODB.Stream chunked reads or a log tool for large files.锁文件
<%
' 简单的互斥:用文件存在与否当锁
If Not fso.FileExists(lockPath) Then
Set ts = fso.CreateTextFile(lockPath, True)
ts.Write "locked"
ts.Close
' 做需要互斥的事
fso.DeleteFile lockPath
End If
%>This file-lock has a race: two requests can both see "no file" and both create it. For real mutual exclusion use Application.Lock or a database row lock, not the filesystem.
属性与方法
| 成员 | 用途 |
|---|---|
| 读 n 个字符 | 按字符读 |
| 读一行 | 不含换行符 |
| 读全部 | 整个文件 |
| 跳过 | 跳过 n 个字符 |
| 跳过一行 | |
| 写 | 不换行 |
| 写一行 | 自动加换行 |
| 写空行 | n 个换行 |
| 是否结束 | 读到末尾为 True |
| 位置 | 当前行列 |
逐行读取
<%
Dim fso, ts, line, n
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set ts = fso.OpenTextFile(Server.MapPath("/data/users.txt"), 1)
n = 0
Do While Not ts.AtEndOfStream
line = ts.ReadLine
n = n + 1
Response.Write n & ": " & Server.HTMLEncode(line) & "<br>"
Loop
ts.Close
Set ts = Nothing
Set fso = Nothing
%>1: Ada,ada@example.com
2: Bob,bob@example.com
3: Cy,cy@example.com用 Do While Not ts.AtEndOfStream 而不是 For i = 1 To N——行数是未知的,硬编码循环次数要么漏读要么读到空行。
逐行写入
<%
Dim rows, i
rows = Array("Ada,ada@example.com", "Bob,bob@example.com")
Set ts = fso.CreateTextFile(Server.MapPath("/data/users.txt"), True)
For i = 0 To UBound(rows)
ts.WriteLine rows(i)
Next
ts.Close
%>CreateTextFile(path, True) 的第二个参数 True 表示「已存在就覆盖」。写成 False 时文件已存在会报错——这个参数很容易漏,漏了就得到「文件已存在」的运行时错误。
解析 CSV
<%
Dim parts
Do While Not ts.AtEndOfStream
parts = Split(ts.ReadLine, ",")
If UBound(parts) >= 1 Then
Response.Write "<tr><td>" & Server.HTMLEncode(parts(0)) & _
"</td><td>" & Server.HTMLEncode(parts(1)) & "</td></tr>"
End If
Loop
%>Split 处理简单 CSV 够用,但遇到「字段里含逗号」或「引号转义」就不行了。真实 CSV 需要按引号状态机解析——Split 会把 "Ada, Jr." 拆成两段。
编码
<%
' 默认按 ASCII 读写,中文会变问号
Set ts = fso.CreateTextFile(path, True, True) ' 第三参数 True = Unicode(UTF-16)
Set ts = fso.OpenTextFile(path, 1, False, -1) ' 第四参数 -1 = Unicode
Set ts = fso.OpenTextFile(path, 1, False, 0) ' 0 = ASCII(默认)
Set ts = fso.OpenTextFile(path, 1, False, -2) ' -2 = 系统默认编码
%>CreateTextFile / OpenTextFile 的编码参数只有 ASCII、Unicode(UTF-16)、系统默认三种,没有 UTF-8。要读写 UTF-8 文件得用 ADODB.Stream,设置 Charset = "utf-8"。
<%
Dim st
Set st = Server.CreateObject("ADODB.Stream")
st.Type = 2 ' 文本
st.Charset = "utf-8"
st.Open
st.LoadFromFile Server.MapPath("/data/utf8.txt")
Response.Write st.ReadText
st.Close
Set st = Nothing
%>TextStream 适合小文件。读几十 MB 的日志时 ReadAll 会把整个文件读进内存,IIS 工作进程的内存直接飙升。大文件要么用 ADODB.Stream 分块读,要么改用日志分析工具。锁文件
<%
' 简单的互斥:用文件存在与否当锁
If Not fso.FileExists(lockPath) Then
Set ts = fso.CreateTextFile(lockPath, True)
ts.Write "locked"
ts.Close
' 做需要互斥的事
fso.DeleteFile lockPath
End If
%>这种「文件锁」在并发下有竞态:两个请求可能同时判断「文件不存在」,然后都创建。真要互斥,用 Application.Lock 或数据库行锁,别用文件系统当锁。