Вопрос

Мне нужно сдвинуть текстовый файл.Я абсолютно ничего не знаю о Perl, но нашел в Perl прекрасно работающий фрагмент кода под названием moz-byteshift.pl (документация).Это именно то, что я хочу, но мне нужно сделать это на C#.

Вот исходный код файла perl:

#!/usr/bin/perl

# To perform a byteshift of 7
#   To decode: moz-byteshift.pl -s -7 <infile >outfile
#   To encode: moz-byteshift.pl -s  7 <infile >outfile

# To perform a byteshift of 13
#   To decode: moz-byteshift.pl -s -13 <infile >outfile
#   To encode: moz-byteshift.pl -s  13 <infile >outfile

use encoding 'latin1';
use strict;
use Getopt::Std;

use vars qw/$opt_s/;

getopts("s:");
if(!defined $opt_s) {
  die "Missing shift\n";
}

my $buffer;
while(1) {
  binmode(STDIN, ":raw");
  my $n=sysread STDIN, $buffer, 1;
  if($n == 0) {
    last;
  }
  my $byte = unpack("c", $buffer);
  $byte += 512 + $opt_s;
  $buffer = pack("c", $byte);
  binmode(STDOUT, ":raw");
  syswrite STDOUT, $buffer, 1;
}

Если бы кто-нибудь мог хотя бы объяснить, как работает Perl-скрипт, было бы здорово.Пример кода эквивалента на C# был бы лучше."="

Спасибо за помощь.

Это было полезно?

Решение

Код делает следующее:Считайте каждый байт из стандартного ввода один за другим (после переключения его в необработанный режим, чтобы не происходило перевода).При распаковке получается значение байта только что прочитанного символа, так что чтение «0» превращается в 0x30.Кодировка Latin1 выбирается таким образом, чтобы это преобразование было последовательным (например,видеть http://www.cs.tut.fi/~jkorpela/latin9.html).

Затем к этому байту добавляется значение, указанное в командной строке с опцией -s, вместе с 512 для имитации операции вычисления модуля.Таким образом, -s 0, -s 256 и т. д. эквивалентны.Я не уверен, зачем это нужно, потому что я предполагал, что следующий пакет позаботится об этом, но я думаю, что у них, должно быть, были веские причины поместить его туда.

Затем запишите необработанный байт на стандартный ввод.

Вот что происходит, когда вы запускаете его с файлом, содержащим символы 012345 (я помещаю данные в ДАННЫЕ раздел):

E:\Test> byteshift.pl -s 1 | xxd
0000000: 3132 3334 3536 0b                        123456.

Каждое значение байта увеличивается на единицу.

E:\Test> byteshift.pl -s 257 | xxd
0000000: 3132 3334 3536 0b                        123456.

Помните: 257 % 256 = 1.То есть:

$byte += $opt_s;
$byte %= 256;

эквивалентно одному шагу, используемому в коде.

Гораздо позже:Хорошо, я не знаю C#, но вот что мне удалось собрать воедино с помощью онлайн-документации.Кто-то, кто знает C#, должен это исправить:

using System;
using System.IO;

class BinaryRW {
    static void Main(string[] args) {
        BinaryWriter binWriter = new BinaryWriter(
                Console.OpenStandardOutput()
                );
        BinaryReader binReader = new BinaryReader(
                Console.OpenStandardInput()
                );

        int delta;

        if ( args.Length < 1 
                || ! int.TryParse( args[0], out delta ) )
        {
            Console.WriteLine(
                    "Provide a non-negative delta on the command line"
                    );
        } 
        else {       
            try  {
                while ( true ) {
                    int bin = binReader.ReadByte();
                    byte bout = (byte) ( ( bin + delta ) % 256 );
                    binWriter.Write( bout );
                }
            }

            catch(EndOfStreamException) { }

            catch(ObjectDisposedException) { }

            catch(IOException e) {
                Console.WriteLine( e );        
            }

            finally {
                binWriter.Close();
                binReader.Close();

            }
        }
    }
}

E:\Test> xxd bin
0000000: 3031 3233 3435 0d0a 0d0a                 012345....

E:\Test> b 0 < bin | xxd
0000000: 3031 3233 3435 0d0a 0d0a                 012345....

E:\Test> b 32 < bin | xxd
0000000: 5051 5253 5455 2d2a 2d2a                 PQRSTU-*-*

E:\Test> b 257 < bin | xxd
0000000: 3132 3334 3536 0e0b 0e0b                 123456....

Другие советы

Рассказывать особо нечего.Он считывает файл по одному байту за раз, корректирует значение каждого байта на произвольное значение (указанное с помощью флага -s) и записывает скорректированные байты.Это двоичный эквивалент шифрования текстового файла ROT-13.

Остальные детали относятся к тому, как Perl делает эти вещи.getopts() — это функция (из модуля Getopt::Std), которая обрабатывает переключатели командной строки.binmode() переводит дескрипторы файлов в необработанный режим, чтобы обойти любую магию, которую обычно выполняет Perl во время ввода-вывода.Функции sysread() и syswrite() используются для доступа к потоку низкого уровня.Функции package() и unpack() используются для чтения и записи двоичных данных;Perl не поддерживает собственные типы.

Это было бы тривиально для повторной реализации в C.Я бы рекомендовал сделать это (и привязать к нему C#, если это необходимо), а не напрямую портировать на C#.

Судя по другим ответам, эквивалент на С# будет выглядеть примерно так:

using(Stream sIn = new FileStream(inPath))
{
  using(Stream sOut = new FileStream(outPath))
  {
    int b = sIn.ReadByte();
    while(b >= 0)
    {
      b = (byte)b+1; // or some other value
      sOut.WriteByte((byte)b);
      b = sIn.ReadByte();
    }
    sOut.Close();
  }
  sIn.Close();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top