我使用C#framework 4.5,netoffice 1.6和sharpdevelop 4.4.1来操作位于网络共享中的Excel工作簿,从Outlook中开始。
在某些时候,我需要将工作簿对象(ewb)的文件访问权限更改为如下所示进行读写:
ewb.ChangeFileAccess(Excel.Enums.XlFileAccess.xlReadWrite, System.Reflection.Missing.Value, true);
在更改文件访问权限之前,我会检查文件是否在服务器上被锁定。如果文件被锁定,我将通知用户稍后重试该操作。
现在,我想在通知中包含锁定excel文件的用户名。我搜索了msdn,netoffice论坛等等,但还没有找到解决方案。 我知道,如果你打开excel文件readwrite,它会将用户的名字存储在xlsx文件中。如何通过c#?
访问该特定信息编辑: 我最终这样做了:
public string GetExcelFileOwner(string path, NetOffice.ExcelApi.Enums.XlFileFormat ffmt) {
string tempmark = "~$";
if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) {
tempmark = "";
}
string uspath = Path.Combine(Path.GetDirectoryName(path), tempmark + Path.GetFileName(path));
if (!File.Exists(uspath)) return "";
var sharing = FileShare.ReadWrite | FileShare.Delete;
using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing))
using (var br = new BinaryReader(fs, Encoding.Default)) {
if(ffmt==NetOffice.ExcelApi.Enums.XlFileFormat.xlExcel8) {
byte[] ByteBuffer = new byte[500];
br.BaseStream.Seek(150, SeekOrigin.Begin);
br.Read(ByteBuffer, 0, 500);
return matchRegex(System.Text.Encoding.UTF8.GetString(ByteBuffer), @"(?=\w\w\w)([\w, ]+)").Trim();
}
else {
return br.ReadString();
}
}
}
private static string matchRegex(string txt, string rgx) {
Regex r;
Match m;
try {
r = new Regex(rgx, RegexOptions.IgnoreCase);
m = r.Match(txt);
if (m.Success) {
return m.Groups[1].Value.ToString();
}
else {
return "";
}
}
catch {
return "";
}
}
我们正在使用excel 2003和excel 2007+文件格式(.xls和.xlsx)。对于.xls,我必须查看.xls文件本身。对于.xlsx,锁定用户存储在〜$ temp文件中。 我知道,对于.xls文件,它是脏代码,但我不知道.xls文件格式是如何构造的。因此,我只读了一堆字节,其中包含ascii用户名并执行正则表达式来提取该用户名。
答案 0 :(得分:8)
它会将用户的名字存储在xlsx文件中
不,不是.xlsx文件。 Excel创建另一个文件来存储用户名。它打开了隐藏文件属性,因此您通常无法使用资源管理器查看它。
它通常与原始文件具有相同的名称,但前缀为~$
。因此,对于名为test.xlsx
的文件,您将获得名为~$test.xlsx
的文件。它是一个二进制文件,包含在默认代码页和utf-16中编码的用户名。十六进制转储以显示它的外观:
0000000000: 0C 48 61 6E 73 20 50 61 │ 73 73 61 6E 74 20 20 20 ♀Hans Passant
0000000010: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20
0000000020: 20 20 20 20 20 20 20 20 │ 20 20 20 20 20 20 20 20
0000000030: 20 20 20 20 20 20 20 0C │ 00 48 00 61 00 6E 00 73 ♀ H a n s
0000000040: 00 20 00 50 00 61 00 73 │ 00 73 00 61 00 6E 00 74 P a s s a n t
0000000050: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000060: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000070: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000080: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
0000000090: 00 20 00 20 00 20 00 20 │ 00 20 00 20 00 20 00 20
00000000A0: 00 20 00 20 00 │
文件中的奇数0x0C字是字符串长度(不是字节),后跟54个字符来存储用户名,用空格填充。最简单的方法是使用BinaryReader.ReadString():
public static string GetExcelFileOwner(string path) {
string uspath = Path.Combine(Path.GetDirectoryName(path), "~$" + Path.GetFileName(path));
if (!File.Exists(uspath)) return "";
var sharing = FileShare.ReadWrite | FileShare.Delete;
using (var fs = new FileStream(uspath, FileMode.Open, FileAccess.Read, sharing))
using (var br = new BinaryReader(fs, Encoding.Default)) {
return br.ReadString();
}
}
但不一定是最正确的方法,如果8位编码在您的语言环境中运行良好,您可能希望改进代码并尝试找到utf-16字符串(不使用ReadString)。 Seek()首先偏移0x37。确保正确使用该方法,它具有隐式竞争条件,因此请确保仅在操作失败后使用并且期望无论如何返回空字符串。我无法保证此方法在所有Excel版本(包括将来的版本)上都能正常工作,我只在工作站类计算机上测试了Office 2013。
答案 1 :(得分:0)
你有哪些问题?
在不了解xslx的情况下,我只能猜测:你想打开文件并指定FileAccess.Read& FileShare.ReadWrite如下:How to read open excel file at C#之后,您使用某种库将XSLX转换为DataTable,并提取您需要的特定行。