0

0

C# NTFS备用数据流 C#如何读写文件的Alternate Data Streams (ADS)

星降

星降

发布时间:2026-02-11 09:47:02

|

724人浏览过

|

来源于php中文网

原创

C#中ADS需通过P/Invoke调用Win32 API操作,System.IO类库完全忽略ADS;读写必须用CreateFile(带FILE_FLAG_BACKUP_SEMANTICS)、ReadFile、WriteFile等,并注意流创建、SetEndOfFile、FlushFileBuffers及句柄释放。

c# ntfs备用数据流 c#如何读写文件的alternate data streams (ads)

ADS在C#中没有原生API支持,必须调用Windows API

Windows .NET运行时(包括.NET Framework、.NET Core 3.1+ 和 .NET 5+)的System.IO类库完全忽略备用数据流——File.ReadAllTextFileStreamFileInfo.Length等所有标准API均无法感知ADS存在。想读写ADS,唯一可靠方式是P/Invoke调用CreateFileSetFilePointerExReadFileWriteFile等Win32函数。

常见错误现象:File.Exists("test.txt:secret")返回falsenew FileInfo("test.txt:secret").Length抛出IOException;直接用File.WriteAllText("test.txt:secret", "data")会静默创建主文件test.txt:secret(即冒号被当作文件名一部分),而非向test.txt写入流。

  • 必须使用CreateFile打开带流名的路径,如"test.txt:secret:$DATA"$DATA可省略,但显式写出更清晰)
  • 打开模式需设为GENERIC_READ | GENERIC_WRITE,访问方式必须含FILE_FLAG_BACKUP_SEMANTICS(否则AccessDenied
  • 句柄必须用CloseHandle显式释放,.NET GC不管理Win32句柄

读取ADS内容的最小可行代码

以下代码片段能安全读取指定ADS(假设流名为secret):

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    IntPtr lpSecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    IntPtr hTemplateFile);

[DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr hObject);

const uint GENERIC_READ = 0x80000000; const uint GENERIC_WRITE = 0x40000000; const uint OPEN_EXISTING = 3; const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;

string filePath = @"C:\temp\test.txt:secret"; IntPtr handle = CreateFile( filePath, GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);

if (handle == new IntPtr(-1)) { int error = Marshal.GetLastWin32Error(); throw new IOException($"Failed to open ADS: {error}"); }

try { var buffer = new byte[4096]; uint bytesRead; if (!ReadFile(handle, buffer, (uint)buffer.Length, out bytesRead, IntPtr.Zero)) { throw new IOException("ReadFile failed"); } string content = Encoding.UTF8.GetString(buffer, 0, (int)bytesRead); } finally { CloseHandle(handle); }

注意:ReadFileWriteFile需自行P/Invoke声明;缓冲区大小应按需调整,ADS通常很小,但无上限限制;若流不存在,CreateFile返回INVALID_HANDLE_VALUE(-1),不是null

写入ADS时容易踩的三个坑

写入比读取更易出错,尤其在流不存在时需正确处理创建逻辑:

谱乐AI
谱乐AI

谱乐AI,集成 Suno、Udio 等顶尖AI音乐模型的一站式AI音乐生成平台。

下载
  • CreateFiledwCreationDisposition必须用CREATE_ALWAYSOPEN_ALWAYS,不能用OPEN_EXISTING(否则流不存在时失败)
  • 写入前未调用SetEndOfFile会导致旧内容残留——ADS不像主文件有自动截断,必须显式收缩长度
  • 写入后未调用FlushFileBuffers,数据可能滞留在内核缓存,其他进程(如资源管理器)立即读不到最新内容

例如覆盖写入test.txt:hidden

IntPtr handle = CreateFile(@"test.txt:hidden:$DATA", 
    GENERIC_WRITE, 0, IntPtr.Zero, CREATE_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero);
// ... WriteFile ...
SetEndOfFile(handle); // 关键:清空原有内容
FlushFileBuffers(handle);
CloseHandle(handle);

ADS路径解析与权限注意事项

ADS路径格式为主文件名:流名[:流类型],其中流类型默认是$DATA,可省略。但以下情况必须注意:

  • 流名不能含\ / : * ? " |,且不能以空格结尾(Windows会截断)
  • NTFS权限独立于主文件:即使用户对test.txt有读写权,也可能因ADS ACL被拒绝——调试时用icacls test.txt /stream:secret检查
  • .NET程序需以管理员权限运行?不一定。只要当前用户对文件有READ_PROPERTIES/WRITE_PROPERTIES权限且启用了备份权限(通常普通用户也有),即可操作ADS;但某些域策略可能禁用SeBackupPrivilege

最常被忽略的是流名编码:Windows内部用UTF-16,但C#字符串已是UTF-16,所以无需额外编码转换;但若从外部输入(如HTTP参数)获取流名,需先验证是否含非法字符,否则CreateFile直接失败且错误码不直观。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

243

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

664

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

486

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1544

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

637

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

821

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

813

2024.04.29

包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法
包子漫画网页版入口与全集阅读指南_正版免费漫画快速访问方法

本专题汇总了包子漫画官网和网页版入口,提供最新章节抢先看方法、正版免费阅读指南,以及稳定访问方式,帮助用户快速直达包子漫画页面,无广告畅享全集漫画内容。

50

2026.02.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
极客学院Java8新特性视频教程
极客学院Java8新特性视频教程

共17课时 | 3.8万人学习

C# 教程
C# 教程

共94课时 | 9.1万人学习

C 教程
C 教程

共75课时 | 4.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号