[Winform]文件操作.之.如何修改文件的短文件名(8.3格式)

shinaterry 2008-03-15 05:20:56
流程说明:

首先在D:根目录下建立: 测试文件示例.txt

接着在开始->运行输入: cmd

[code=BatchFile]C:\> D:
D:\> dir /x[/code]

然后在输出的文件清单当中你会看到: 测试文件示例.txt 前面系统会自动生成一(8.3)格式的短文件名: 测试文~1.TXT

我的目的是想将 测试文~1.TXT 修改成 TEST~1.TXT(自定义)

最后在程序中直接使用 d:\TEST~1.TXT 访问 测试文件示例.txt

希望大家帮帮忙..

哭诉一下: kernel32.dll 提供了相应的 API.GetShortPathName 获取短文件名, 却没有对应的 SetShortPathName 修改短文件名...

发贴告示:

由于 Ivony 推行的新政策, 可能这是最后一次在C#版块散分, 为了庆祝升星(秘密散分) 冒险也要散一散喔...

要散就散个好意头, 178(一起发) ...

^ō^
...全文
1644 87 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
87 条回复
切换为时间正序
请发表友善的回复…
发表回复
wynlc 2010-09-03
  • 打赏
  • 举报
回复
学习了
shinaterry 2008-04-09
  • 打赏
  • 举报
回复
测试成功: 解决方案在73楼上..

调用方式: Modify(@"d:\测试文件示例.txt", "TEST~1.TXT"); //注意参数格式..

履行承诺: 须然原意是要求在 FAT32 卷上实现! 但考虑到, 多次得到 shrinerain 热心帮忙, 决定送分 200 ..

同时感谢: 各位朋友的支持与提供多方面的线索, 酌情给分..
shinaterry 2008-04-08
  • 打赏
  • 举报
回复
谢谢! 一会试试, 测试成功马上结帖; 另外, FAT 真的没有办法修改? 哪怕是一丁点线索..
vrhero 2008-04-08
  • 打赏
  • 举报
回复
这个问题在FAT32(包括FAT16)中用C#应该是不可能实现的...因为只能通过改写FAT中的文件名实现...而直接操作FAT需要取得系统的0环控制权...据我所知得写底层驱动才行...当然我是菜鸟孤陋寡闻也不一定...

至于原因...去了解一下文件系统知识就知道了...FAT32和FAT16都将文件名存储于FAT...不同的是FAT32还有一个长文件名存储区...而NTFS和FAT的原理不同可以存储附加的文件信息...

8.3短文件名对NTFS来说只是一个附加信息仅仅用于兼容部分旧应用程序...而对FAT32来说则必须遵从标准以兼容旧操作系统...为了防止短文件名重名没有提供重命名短文件名的方法...是由操作系统控制的...

至于那些能够修改短文件名的软件应该是通过底层驱动实现的...C++的作品...
shrinerain 2008-04-08
  • 打赏
  • 举报
回复
虚拟机? 你在你本机上试试吧.
shinaterry 2008-04-08
  • 打赏
  • 举报
回复
55见鬼了! 我也是用VS2005, 难道是跟操作系统环境有关? 我是用 虚拟机->Windows 2000 专业版->NTFS 进行测试..
shrinerain 2008-04-08
  • 打赏
  • 举报
回复
从这个图片你也可以看到我是修改成功了的. 系统已经找不到 测试文~1.TXT
shrinerain 2008-04-08
  • 打赏
  • 举报
回复
如果图太小... 到这看
http://ftsqmw.bay.livefilestore.com/y1p5G40IyA6x4W6STAO1h-mUEepBwdGCUMp2Mxg8bGZgMadG338smlynTwvaVnjTIm_JmFnIqMmz6xTBq3oUS4wNA/shortname.JPG

我的是VS2005
shrinerain 2008-04-08
  • 打赏
  • 举报
回复
恩?

我copy了你的代码, 在我的机器上执行成功的, 一切OK.

除了添加个GetLastError看看错误代码以外, 我基本没有修改.

我的机器是Windows XP SP2英文版.

shrinerain 2008-04-08
  • 打赏
  • 举报
回复
[Quote=引用 84 楼 shinaterry 的回复:]
谢谢! 一会试试, 测试成功马上结帖; 另外, FAT 真的没有办法修改? 哪怕是一丁点线索..
[/Quote]

我不清楚... 不过我觉得你的要求通过Hook文件操作能更好实现.
shinaterry 2008-04-07
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace ModifyShortFilename
{
class Program
{
//
// Access Token constants: OpenProcessToken.DesiredAccess
//

public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;

//
// Token Privileges constants
//

public const string SE_RESTORE_NAME = "SeRestorePrivilege";

//
// Token Privileges constants
//

public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;

/// <summary>
///
/// </summary>
public const Int32 ANYSIZE_ARRAY = 1;

[Flags]
public enum EFileAccess : uint
{
GenericAll = 0x10000000,
GenericExecute = 0x20000000,
GenericWrite = 0x40000000,
GenericRead = 0x80000000
}

[Flags]
public enum EFileShare : uint
{
None = 0x00000000,
Read = 0x00000001,
Write = 0x00000002,
Delete = 0x00000004
}

public enum ECreationDisposition : uint
{
New = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
}

[Flags]
public enum EFileAttributes : uint
{
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}

[
StructLayout(LayoutKind.Sequential)
]
public struct LUID
{
public UInt32 LowPart;
public Int32 HighPart;
}

[
StructLayout(LayoutKind.Sequential)
]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}

[
StructLayout(LayoutKind.Sequential)
]
public struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
[
MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)
]
public LUID_AND_ATTRIBUTES[] Privileges;
}

[
DllImport("Advapi32.dll", SetLastError = true)
]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

[
DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
[
return: MarshalAs(UnmanagedType.Bool)
]
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

[
DllImport("Advapi32.dll", SetLastError = true)
]
[
return: MarshalAs(UnmanagedType.Bool)
]
public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, [MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGES NewState, UInt32 BufferLength, IntPtr PreviousState, /*IntPtr*/ UInt32 ReturnLength);

[
DllImport("Kernel32.dll")
]
public static extern IntPtr GetCurrentProcess();

[
DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
public static extern IntPtr CreateFile(string lpFileName, EFileAccess dwDesiredAccess, EFileShare dwShareMode, IntPtr lpSecurityAttributes, ECreationDisposition dwCreationDisposition, EFileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);

[
DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
static extern IntPtr CreateFile(string fileName, [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, int flags, IntPtr template);

[
DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
static extern bool SetFileShortName(IntPtr hFile, string lpShortName);

[
DllImport("Kernel32.dll", SetLastError = true)
]
[
return: MarshalAs(UnmanagedType.Bool)
]
static extern bool CloseHandle(IntPtr hObject);

/// <summary>
/// 程序入口.
/// </summary>
static void Main(string[] args)
{
if (Adjust(SE_RESTORE_NAME, true))
{
Console.Write(Modify(@"c:\测试文件示例.txt", "TEST~1.TXT"/*d:\TEST~1.TXT*/) ? "成功" : "失败");

Console.Write(Modify(@"c:\测试文~1.TXT", "TEST~1.TXT") ? "成功" : "失败");

Adjust(SE_RESTORE_NAME, false);
}

Console.Read();
}

/// <summary>
/// 调整特权.
/// </summary>
static bool Adjust(string privilege, bool enabled)
{
IntPtr hToken; bool result = false;

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, out hToken))
{
LUID privilegeId;

if (LookupPrivilegeValue(null, privilege, out privilegeId))
{
TOKEN_PRIVILEGES prives = new TOKEN_PRIVILEGES();

prives.PrivilegeCount = 1;
prives.Privileges = new LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY];
prives.Privileges[0].Luid = privilegeId;
prives.Privileges[0].Attributes = enabled ? SE_PRIVILEGE_ENABLED : 0;

result = AdjustTokenPrivileges(hToken, false, ref prives, (UInt32)Marshal.SizeOf(typeof(TOKEN_PRIVILEGES)), IntPtr.Zero, 0);
}

CloseHandle(hToken);
}

return result;
}

/// <summary>
/// 修改名称.
/// </summary>
static bool Modify(string path, string filename)
{
IntPtr handle = CreateFile(path, EFileAccess.GenericAll, EFileShare.None, IntPtr.Zero, ECreationDisposition.OpenExisting, EFileAttributes.BackupSemantics, IntPtr.Zero);

if (handle != new IntPtr(-1))
{
bool result = SetFileShortName(handle, filename);

CloseHandle(handle);

return result;
}

return false;
}

}
}


@shrinerain 设置 SE_RESTORE_NAME 特权之后, 还是不行, (错误)情况与之前一样啊..
itfutao 2008-04-04
  • 打赏
  • 举报
回复
接分!
shrinerain 2008-04-04
  • 打赏
  • 举报
回复
在MSDN的说明中, 这个函数你需要注意以下几点,

在你调用CreateFile打开时,
1. FileAccess参数必须是GENERIC_ALL或者GENERIC_WRITE|DELETE.
2. flag参数必须为FILE_FLAG_BACKUP_SEMANTICS.

const uint GENERIC_ALL = (uint)0x10000000L;
const uint FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;



此外,你必须在程序中给自己进程设置SE_RESTORE_NAME权限, 这是一个特殊权限.
3. google "Enabling and Disabling Privileges in C++"
mimekoco 2008-04-04
  • 打赏
  • 举报
回复
友情帮顶
shinaterry 2008-04-04
  • 打赏
  • 举报
回复
基于 shrinerain 所提供的线索, 写了以下代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace ModifyShortFilename
{
class Program
{
[
DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
static extern IntPtr CreateFile(string fileName, [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, [MarshalAs(UnmanagedType.U4)] FileShare fileShare, IntPtr securityAttributes, [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, int flags, IntPtr template);

[
DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)
]
static extern bool SetFileShortName(IntPtr hFile, string lpShortName);

[
DllImport("Kernel32.dll", SetLastError = true)
]
[
return: MarshalAs(UnmanagedType.Bool)
]
static extern bool CloseHandle(IntPtr hObject);

static void Main(string[] args)
{
Console.Write(Modify(@"d:\测试文件示例.txt", "TEST~1.TXT"/*d:\TEST~1.TXT*/) ? "成功" : "失败");

//Console.Write(Modify(@"d:\测试文~1.TXT", "TEST~1.TXT") ? "成功" : "失败");

Console.Read();
}

static bool Modify(string path, string filename)
{
IntPtr handle = CreateFile(path, FileAccess.ReadWrite, FileShare.None, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);

if (handle != new IntPtr(-1))
{
bool result = SetFileShortName(handle, filename);

CloseHandle(handle);

return result;
}

return false;
}
}
}


测试结果:

FAT32 分区下用多种参数形式调用 Modify 结果提示"失败", 于是使用 GetLastError 获取错误原因"拒绝访问。".

查阅得知 SetFileShortName 要在 NTFS 分区执行, 觉得现在 FAT32 分区使用报错也是理所当然! 无奈之下, 特意将原来的 FAT32 格式化为 NTFS 分区, 谁知一运行程序就"异常中止", 原因不明..

郁闷, 谁能告诉我是什么原因, 是否我使用不正确, 欢迎 shrinerain 指正, 同时希望大家帮忙测试测试..
shrinerain 2008-03-24
  • 打赏
  • 举报
回复
[Quote=引用 68 楼 shinaterry 的回复:]
引用 67 楼 youngerch 的回复:
这题比较狠


^ō^ 此话何解?


To: shrinerain ...

首先感谢您的关注! 实际上我的真正的商业需求确实只须跨越这个屏障(重写短文件名)就可以实现了...

目的就是扰乱系统与文件地址之间的对应关系, 为后面的文件加密加多一层保护...

加强加密的隐蔽性...
[/Quote]

哦... 这样子, 其实你可以通过Hook CreateFile等几个函数来实现你的目的.

在CreateFile/CreateFileEx等几个文件操作函数里面, 如果传入参数是特定文件名, 则修改文件名, 调用真正的文件.

比如, 系统是想打开111.txt, 你拦截这个操作, 让系统实际打开的是222.txt, 这样可以达到你隐藏222.txt的目的, 因为外部程序看起来它打开的是111.txt.

shinaterry 2008-03-24
  • 打赏
  • 举报
回复
[Quote=引用 67 楼 youngerch 的回复:]
这题比较狠
[/Quote]

^ō^ 此话何解?


To: shrinerain ...

首先感谢您的关注! 实际上我的真正的商业需求确实只须跨越这个屏障(重写短文件名)就可以实现了...

目的就是扰乱系统与文件地址之间的对应关系, 为后面的文件加密加多一层保护...

加强加密的隐蔽性...
shrinerain 2008-03-24
  • 打赏
  • 举报
回复
[Quote=引用 70 楼 shinaterry 的回复:]
关于 CreateFile/CreateFileEx, 能提供示例或相关资料?

另外 CreateFile/CreateFileEx..能防止DOS直接操作吗?

比如:del xxx.txt -> 能拦截吗?
[/Quote]

命令行!=DOS

去Google "Hook CreateFile", 你可以搜到一堆C++代码, 因为API hook是不能用.Net的.

一般情况你Hook这些API函数. 至于Del命令具体是怎么执行的, 你可以用softice跟踪一下.
CloseHandle
CreateDirectory
CreateDirectoryEx
CreateFileTransacted
CreateMailSlot
CreateNamedPipe
DeleteFile
OpenFile
ReadFile
ReadFileEx
WriteFile
WriteFileEx

wanabe 2008-03-24
  • 打赏
  • 举报
回复
up
shinaterry 2008-03-24
  • 打赏
  • 举报
回复
关于 CreateFile/CreateFileEx, 能提供示例或相关资料?

另外 CreateFile/CreateFileEx..能防止DOS直接操作吗?

比如:del xxx.txt -> 能拦截吗?
加载更多回复(59)

111,094

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧