使用文件的内容重命名它

时间:2013-06-11 10:24:26

标签: string file batch-file vbscript

我的二进制数据文件大小约为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组合。

这似乎是重复的,但原始问题缺乏细节,错误地集中在批处理上,并且给出的答案是不够的。

2 个答案:

答案 0 :(得分:1)

  

注意该文件似乎是“Composite Document File V2 Document”格式。有可能的库可以以适当的方式阅读。

     

狂野猜测:你是否试图“阅读”Outlook .msg文件,word / excel文件?

     

使用file或查看

     

更新添加了C ++版本(见下文

对该文件的一点点攻击告诉我它是一个二进制文件,字符串没有分隔,但前面是它们的长度字节。所以,这个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 ++版

为了好玩,我写了一个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());
    }
}

你以完全相同的方式使用它。当然,您可以将此打印改为newname,并在您自己的脚本中使用它。 编辑编辑版本为交叉编译到win-exe。使其打印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