从字节数组或流中获取文件名是否可能?我只想检索文件名,而不是保存文件。
Stream
实际上是一个FileStream
,那么可以通过将其转换为FileStream
类型并访问.Name
属性来获取此信息。Stream stream = ...
FileStream fs = stream as FileStream;
if(fs != null) Console.WriteLine(fs.Name);
然而,在一般情况下,不是所有的流都提供文件名,包括byte[]
和大多数其他类型的流。同样地,即使底层流(在几个层次下)是一个文件,被其他流(如压缩、加密、缓冲等)包装的FileStream
基础流也不会显示这些信息。
我建议将文件名单独处理。
不,这是不可能的(好的,也许在 FileStream
类上可能是可能的,每天都能学到新东西!)。
一个字节数组或流代表着文件的内容,而不是Windows关于文件的元数据。
有很多简单的方法可以保留这些信息,但不知道更多关于您情况的信息,我无法提供解决方案。
所有文件信息(如名称、扩展名等)都是实际文件的元数据。字节数组仅包含实际数据。如果字节数组本身包含元数据(例如一个XML文件),则可能是可行的...但是,您需要知道类型和具体查找位置。
你无法从字节数组中获取文件名。相反,你需要使用文件流来获取文件名。字节数组不存储名称。
public string GetOriginalFilenameFromStream(Stream stream)
{
if (stream == null)
return null;
string lookupString = "O\0r\0i\0g\0i\0n\0a\0l\0F\0i\0l\0e\0n\0a\0m\0e"; // OriginalFilename with null char between each letter
int originalFileNameLength = 550; // I bit more than 512 (256 * 2 (for the nulls)) + the possible extensions
//Go at the end of the stream
stream.Seek(0, SeekOrigin.Begin);
long currentPosition = 0;
bool hasFoundBytes = false;
byte[] bit = new byte[1] { 0 };
char[] lookupStringChars = lookupString.ToCharArray();
byte[] lookupBytes = Encoding.ASCII.GetBytes(lookupStringChars);
do
{
for (int i = 0; i < lookupBytes.Length; i++)
{
if (bit[0] == lookupBytes[i])
{
hasFoundBytes = true;
if (i == lookupBytes.Length - 1)
break; // Stops reading if the end of the lookupBytes has been reached (string has been found)
else
currentPosition = stream.Read(bit, 0, 1);
}
else
{
hasFoundBytes = false;
currentPosition = stream.Read(bit, 0, 1);
break;
}
}
} while (currentPosition != 0 && !hasFoundBytes && stream.Position < 1073741824 /* 1 MB */);
if (!hasFoundBytes)
{
// Lookup not found in the file
return null;
}
// Gets the OriginalFilename from the stream
byte[] originalFilenameByteArray = new byte[originalFileNameLength];
stream.Read(originalFilenameByteArray, 0, originalFileNameLength);
string parsedOriginalFilename = ParseOriginalFilename(Encoding.ASCII.GetString(originalFilenameByteArray));
_logWriter?.Info($"{this.GetType().Name} {nameof(GetOriginalFilenameFromStream)} returns {parsedOriginalFilename}");
return parsedOriginalFilename;
string ParseOriginalFilename(string stringToParse)
{
// Gets the text between the 2 first 3 nulls \0\0\0
string nullChar = "\0";
string threeNulls = string.Format("{0}{0}{0}", nullChar);
int pFrom = stringToParse.IndexOf(threeNulls) + threeNulls.Length;
int pTo = stringToParse.IndexOf(threeNulls, pFrom);
string originalFilename = stringToParse.Substring(pFrom, pTo - pFrom);
// Removes the nulls between each letters
originalFilename = originalFilename.Replace(nullChar, "");
return originalFilename;
}
}
O\0r\0i\0g\0i\0n\0a\0l\0F\0i\0l\0e\0n\0a\0m\0e\0\0\0T\0e\0s\0t\0A\0p\0p\0.\0e\0x\0e\0\0\0...
解析后的原始文件名如下:
TestApp.exe
希望这可以帮到您。function Get-AppInfoFromBytes{
[CmdletBinding()]
param(
$bytes,
[string]
$VersionInfo="OriginalFilename"
)
if ( $bytes -IsNot [byte[]] ) {throw 'byte data required';}
if ( $bytes.Length -gt 80kb -Or $bytes.Length -lt 3kb ) {write-warning 'A BYTE LENGTH OF 80KB MAX OR 3KB MIN FROM HEAD OR TAIL OF A FILE IS ENOUGH TO CONTAIN THE INFO';}
# preserving the nullchar effect in string
[string]$lookupString = iex -command "echo $( ($VersionInfo -replace '(.)','`0$1').remove(0,2) )"
[int16]$AppInfoValueLength = 550; # // I bit more than 512 (256 * 2 (for the nulls)) + the possible extensions
write-verbose "searching property `"$lookupString`""
[int32]$position=0
$position=([System.Text.Encoding]::ASCII.GetString($bytes)).Indexof($lookupString)
if ($Position -eq -1) {
write-verbose "VersionInfo `"$VersionInfo`" property was not Found`nplease check other properties or supply another bytes portion"
return $null;
}
write-verbose "Gets the Info from byte data...note that even the info exist it may contain an empty string"
[byte[]]$bytes=$bytes[$position..($position+$AppInfoValueLength)]
[string]$S=[System.Text.Encoding]::ASCII.GetString($bytes);
$3Nuls = "`0`0`0"
$3NulsStartIdx1 = $S.IndexOf($3Nuls) + 3
$3NulsStartIdx2 = $S.IndexOf($3Nuls, $3NulsStartIdx1);
return $S.Substring($3NulsStartIdx1,$3NulsStartIdx2-$3NulsStartIdx1).Replace("`0", "" )
}
#getting the bytes methods:
PS > [byte[]]$bytes=cat "C:\Users\Zdilto\Desktop\File.exe" -tail 3kb -enc byte
PS > $bytes=cat "C:\Users\Zdilto\Desktop\File.exe" -total 76kb -AsByteStream
PS > $bytes=[io.file]::ReadAllBytes("C:\Users\Zdilto\Desktop\File.exe")
PS > $bytes=$bytes[0..10kb]
#calling the function:
PS > Get-AppInfoFromBytes -b $bytes -verbose;
PS > Get-AppInfoFromBytes -b $bytes -v "LegalCopyright" -verbose;
PS > Get-AppInfoFromBytes -b $bytes -v "InternalName";
PS > Get-AppInfoFromBytes -b $bytes -v "ProductName";
PS > Get-AppInfoFromBytes -b $bytes -v "Comments" -verbose;
#testing result:
PS > $result=Get-AppInfoFromBytes -byte $bytes -VersionInfo Comments -verbose;
PS > if( [string]::IsNullOrEmpty($result) ) {"got no value"} else {"success"}