我的二进制数据文件大小约为20 MB,并且具有随机文件名,所有文件都以“AA”开头。在每个文件的内容中,它们在固定位置具有特定字符串(在从第2086字节开始的所有文件中)。我想读取由2个单词组成的字符串(中间有1个空格,如下例中的“MyName Sirname”),并将其与文件创建日期一起使用以重命名文件。
这是一个缩短的示例文件(第一个3Kb):
dl.dropboxusercontent.com/u/18286876/short.zhr
我们要将此特定文件重命名为“MyName Sirname YYYY-MM-DD”。
最好是脚本遍历currant目录中以“AA”开头的所有文件。无论什么都是简单的,脚本可以是vbs或batch + vbs组合。
这似乎是重复的,但原始问题缺乏细节,错误地集中在批处理上,并且给出的答案是不够的。
答案 0 :(得分:1)
注意该文件似乎是“Composite Document File V2 Document”格式。有可能的库可以以适当的方式阅读。
狂野猜测:你是否试图“阅读”Outlook
.msg
文件,word / excel文件?使用
file
或查看
对该文件的一点点攻击告诉我它是一个二进制文件,字符串没有分隔,但前面是它们的长度字节。所以,这个bash脚本应该可以正常工作:
#!/bin/bash
set -e # stop on errors
for originalname in "$@"
do
# get lengths
first_len=$(od -j 2085 "$originalname" -An -t u1 -N1)
second_len=$(od -j $((2086 + $first_len)) "$originalname" -An -t u1 -N1)
# strip whitespace
read first_len second_len <<< "$first_len $second_len"
# extract the words as text
firstword=$(dd if="$originalname" bs=1 skip=2086 count=$first_len)
secondword=$(dd if="$originalname" bs=1 skip=$((2087+$first_len)) count=$second_len)
# calculate new name, using the timestamp of the file too:
newname="$firstword $secondword $(date -r "$originalname" +"%Y-%m-%d")"
# do the move (verbosely)
mv -v "$originalname" "$(dirname "$originalname")/$newname"
done
我在你提供的文件上测试了它:
$ ./test.sh short.zhr 2>/dev/null
`short.zhr' -> `./MyName Sirname 2013-06-11'
你必须喜欢UNIX哲学:)
对于您的情况,您可以运行
./test.sh somedir/AA*
为了好玩,我写了一个C ++版本。这应该很容易携带。
它实际上更具可读性(除了格式化时间戳的部分......)。
#include <string>
#include <vector>
#include <fstream>
#include <ctime>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>
std::string extract_string(std::istream& is) {
char len;
if (is && is.read(&len, 1)) {
std::string result(len, '\0');
is.read(&*result.begin(), len);
return result;
}
return "";
}
std::string timestamp(std::string const& fname, const char* fmt = "%Y-%m-%d")
{
struct stat sb;
if (-1 == stat(fname.c_str(), &sb))
perror("cannot get file stats");
if (struct tm* tmp = localtime(&sb.st_ctime))
{
std::string buf(200, '\0');
buf.resize(strftime(&*buf.begin(), buf.size(), fmt, tmp));
return buf;
} else
perror("localtime failed");
return "";
}
int main(int argc, const char *argv[])
{
for (int i = 1; i<argc; ++i)
{
const std::string fname(argv[i]);
std::ifstream stream(fname.c_str(), std::ios::binary);
stream.seekg(2085);
std::string first = extract_string(stream);
std::string second = extract_string(stream);
std::string newname = first + " " + second + " " + timestamp(fname);
std::cout << (("rename \"" + fname + "\" \"" + newname + "\"").c_str());
}
}
你以完全相同的方式使用它。当然,您可以将此打印改为 编辑编辑版本为交叉编译到win-exe。使其打印newname
,并在您自己的脚本中使用它。rename
命令。
答案 1 :(得分:1)
这样的事情可能有用,假设你的所有文件都在同一个文件夹中C:\some\where
:
Const offset = 2085
Set fso = CreateObject("Scripting.FileSystemObject")
For Each f In fso.GetFolder("C:\some\where").Files
If Left(f.Name, 2) = "AA" Then
Set stream = f.OpenAsTextStream
stream.Skip(offset)
words = Array()
Do
length = Asc(stream.Read(1))
If length <> 0 Then
ReDim Preserve words(UBound(words)+1)
words(UBound(words)) = stream.Read(length)
End If
Loop Until length = 0 Or stream.AtEndOfStream
stream.Close
If UBound(words) >= 1 Then
fdate = Year(f.DateCreated) & "-" & Right("0" & Month(f.DateCreated), 2) _
& "-" & Right("0" & Day(f.DateCreated), 2)
f.Name = words(0) & " " & words(1) & " " & fdate _
& "." & fso.GetExtensionName(f.Name)
End If
End If
Next