【问题标题】:IO FileStream and StreamReader in Powershell return null while in c# it does workPowershell 中的 IO FileStream 和 StreamReader 返回 null 而在 c# 中它确实有效
【发布时间】:2020-03-20 09:18:42
【问题描述】:

我用 C# 创建了一个脚本,出于个人原因,我想在 PowerShell 中转换它。

试了很多次还是不明白为什么还是这个错误,是不是代码有问题?

"不能在 Null 表达式中调用方法。" |当我调用 $reader.ReadLine()

此脚本的目标是读取 .log 文件,并找到有用的信息将它们发送到 MongoDB 数据库。

C#

            string level = "", username = "", date = "", solutionName = "", message = "";
        FileStream logFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        StreamReader reader = new StreamReader(logFileStream);

        int compteur = 0;

        while (compteur < lineCount-1)
        {
            bool info = true;
            string messagelog = "";
            int tmpCompteur = 0;
            // open the file to read it
            reader = File.OpenText(filePath);
            // take the log message (could be multiple lines)
            for (int i = 0; i < lineCount; i++)
            {
                string line = reader.ReadLine();
                if (Regex.IsMatch(line, "INFO") || Regex.IsMatch(line, "ERROR"))
                {
                    if (info)
                        info = !info;
                    else
                        break;
                }
                messagelog += line;
                tmpCompteur++;
                compteur++;
            }

            // Regex to find the log Level, UserName, Date, SolutionName, Message
            if (Regex.IsMatch(messagelog, "INFO") || Regex.IsMatch(messagelog, "ERROR"))
                level = Regex.Match(messagelog, "INFO").Value;
            if (Regex.IsMatch(messagelog, "-(.*?)-"))
                username = Regex.Match(messagelog, "-(.*?)-").Value.Substring(1, Regex.Match(messagelog, "-(.*?)-").Value.Length - 2);
            if (Regex.IsMatch(messagelog, "([1-9]|([012][0-9])|(3[01]))\\/([0]{0,1}[1-9]|1[012])\\/\\d\\d\\d\\d [012]{0,1}[0-9]:[0-6][0-9]:[0-6][0-9]"))
                date = Regex.Match(messagelog, "([1-9]|([012][0-9])|(3[01]))\\/([0]{0,1}[1-9]|1[012])\\/\\d\\d\\d\\d [012]{0,1}[0-9]:[0-6][0-9]:[0-6][0-9]").Value;
            if (Regex.IsMatch(messagelog, "\\[E(.*?)\\]"))
                solutionName = Regex.Match(messagelog, "\\[E(.*?)\\]").Value;
            if (Regex.IsMatch(messagelog, "\\]\\s.*"))
                message = Regex.Match(messagelog, "\\]\\s.*").Value.Substring(2);

            // close the reader because we don't need it anymore
            reader.Close();
            // convert our data to an object to send it to MongoDB
            var Data = new BsonDocument
            {
                { "Date", DateTime.ParseExact(date, "dd/MM/yyyy HH:mm:ss", null) },
                { "Level", level},
                { "Message", message},
                { "UserName", username}
            };
            // send data to MongoDB
            collection.InsertOneAsync(Data);
            // delete the lines already processed by our programm
            File.WriteAllLines(filePath, File.ReadAllLines(filePath).Skip(tmpCompteur).ToArray());
        }
        // close the fileStream
        logFileStream.Close();
        // delete the file
        File.Delete(filePath);
    }

PowerShell

   [string]$level
   [string]$userName
   [string]$date
   [string]$solutionName
   [string]$message

   $logFileStream = New-Object System.IO.FileStream $filePath, ([System.IO.FileMode]::Append), ([System.IO.FileAccess]::Write), ([System.IO.FileShare]::Read)
   $reader = New-Object System.IO.StreamReader $logFileStream
   # https://github.com/nightroman/Mdbc
   Connect-Mdbc -ConnectionString $iniContent["MongoDB"]["Server"] -DatabaseName $iniContent["MongoDB"]["Database"] -CollectionName $iniContent["MongoDB"]["Collection"]
   $pbar_LoadFile.Visible = $true
   [int]$compteur = 0
   while ($compteur -clt $linesCount) {

       [bool]$info = $true 
       [string]$messageLog = ""
       [int]$tmpCompteur = 0
       $reader = $IOFile::OpenText($filePath)
       for ([int]$i = 0; $i -lt $linesCount; $i++) {

           $line = $reader.ReadLine() 
           if ($line -match "INFO") {

               if ($info -eq $true) {

                   $info = $false 
               }
               else {
                   break 
               }
           }
           $messageLog += $line 
           $tmpCompteur++
           $compteur++ 
       }


       if ($messageLog -match "INFO") {

           $level = $matches[0]
       }
       if ($messageLog -match "-(.*?)-") {

           $userName = $matches[0].Substring(1, $matches[0].length - 2)
       }
       if ($messageLog -match "([1-9]|([012][0-9])|(3[01]))\/([0]{0,1}[1-9]|1[012])\/\d\d\d\d [012]{0,1}[0-9]:[0-6][0-9]:[0-6][0-9]") {

           $date = $matches[0]
       }
       if ($messageLog -match "    ") {

           $solutionName = $matches[0]
       }
       if ($messageLog -match "\]\s.*") {

           $message = $matches[0].Substring(2) 
       }
       $reader.Close()       
       @{Date = Convert-ToDateTime($date); Level = $level; Message = $message; UserName = $userName } | Add-MdbcData
       (Get-Content $filePath | Select-Object -Skip $tmpCompteur) | Set-Content $filePath
   }
   $logFileStream.Close()
   Remove-Item $filePath
   $pbar_LoadFile.Value += 1
}

【问题讨论】:

  • 当您从 C# 直接翻译到 PowerShell 时,这看起来像 pidgin PowerShell...为了改进您的 PowerShell 语法,我建议您花一些时间在复杂的 PowerShell pipeline .一般来说,你的脚本应该像这样流式传输:Get-Content $InFile | ForEach-Object { ... } | Set-Content $OutFile

标签: c# powershell system.io.file


【解决方案1】:

您将 System.IO.StreamReader 误解为 $IOFile。您必须首先在 $reader 中声明它,如下所示:

$reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $filePath

在 powershell .NET 中,类型是这样调用的:

[System.IO.File]

它们的静态方法通过在]后面放置两个冒号来调用。

【讨论】:

  • 我忘记写了,但是我之前把它设置为变量,$IOFile = [System.IO.File]
猜你喜欢
  • 2010-09-22
  • 1970-01-01
  • 2012-10-25
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 2019-01-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多