DOBON.NET DOBON.NETプログラミング掲示板過去ログ

標準エラーの取得方法

環境/言語:[WinXP、VB.NET、.NET Frameword 2.0]
分類:[.NET]

2009/06/29(Mon) 15:15:39 編集(投稿者)

こんにちは、おさといいます。

現在、SFTPでファイル転送をするという要件があり、
vb.net(.Net 2.0)からPuttyに付属のpsftp.exeをコントロールして
ファイル転送を行う処理を書いています。
標準出力と標準エラーの内容を見ながら、処理を行っていくように
コードを書いているのですが、標準エラーの内容が取得できずに困っております。

以下のようなコードを書いています。
NowOutputに、コンソールへ出力される文字列が入ることを想定しています。
' ----- ここから -----
conn_process = New Process
conn_process.StartInfo.FileName = "psftp.exe"
conn_process.StartInfo.Arguments = "-2"

'出力を読み取れるようにする
conn_process.StartInfo.RedirectStandardInput = True
conn_process.StartInfo.RedirectStandardOutput = True
conn_process.StartInfo.RedirectStandardError = True
conn_process.StartInfo.UseShellExecute = False
'ウィンドウを表示しないようにする
conn_process.StartInfo.CreateNoWindow = True

conn_process.Start()

Dim stdoutWatcher As Thread = New Thread(New ParameterizedThreadStart(AddressOf standardOutputWatchingThread))
stdoutWatcher.Start(conn_process.StandardOutput)
Dim stderrWatcher As Thread = New Thread(New ParameterizedThreadStart(AddressOf standardOutputWatchingThread))
stderrWatcher.Start(conn_process.StandardError)

conn_process.WaitForExit()

' 出力を読み取るメソッド
Private Sub standardOutputWatchingThread(ByVal parameter As Object)

Dim reader As StreamReader = parameter
While Not reader.EndOfStream
Dim c As Char = Chr(reader.Read())
SyncLock NowOutput
NowOutput &= c
processing() ' バッファの内容を見て処理を行う
End SyncLock
End While
reader.Close()

End Sub
' ----- ここまで -----

このとき、NowOutputにて標準出力の内容は読み取れるのですが、
パスワードを間違えたりしたときに出力される「Access denied」など
標準エラーに出力される内容が出てきません。
stderrWatcherに指定するメソッドを標準出力とわけてみましたが、
全く呼ばれていませんでした。


このため標準エラーを標準出力にリダイレクトしてみようと、
StartInfo.Argumentsに「2>&1」を入れてみたりしたのですが、効果は
ありませんでした。(StartInfo.RedirectStandardError = Trueの時点で意味がない?)

コマンドラインから手動で「(psftp.exe 2>&1) > log.txt」とすると、
標準エラーの内容も取れることは確認したのですが…。

なので、vb.net側の呼び出し方が悪いのだろうと思うのですが、
原因が分かりません。
何かまずい所など、指摘して頂けると助かります。

よろしくお願いいたします。
■No24836に返信(おささんの記事)
> 現在、vb.net(.Net 2.0)からPuttyに付属のpsftp.exeをコントロールして
> ファイル転送を行う処理を書いています。

  外部ソフトの制御で、わざわざ余計に難しくなっていますが・・・

  http://dobon.net/vb/dotnet/internet/index.html

  .NETで提供されているクラス使ったらダメなんですか?

※ ソケット通信で直接FTPすることも可能ですが・・・

以上。
すいません、一番大事な前提条件を書き忘れていました。
SFTPにてファイル転送を行いたいのです。

質問文も修正いたしました。
■No24840に返信(おささんの記事)
> すいません、一番大事な前提条件を書き忘れていました。
> SFTPにてファイル転送を行いたいのです。

  フリーのSSHコンポーネント使ってFTPしたらダメですか?

※ 私は未使用です・・・

※ SSLではなく、SSH?
  SSLが使えるなら、FtpWebRequestクラスで可能かも・・・
  FtpWebRequest.EnableSsl 参照

以上。参考まで
あくまで参考

http://www.bitvise.com/ftp-bridge

こんなものもあります。

以上。
SSLだと、.Netのクラスで行けるんですよねぇ。
SSHも標準で対応して欲しいですねぇ。
(検索しているときに、同じことをつぶやいている外人さんがおられました)

http://www.bitvise.com/ftp-bridge
GUIだけで、自動的に接続・切断が出来そうにないのです…。

標準エラーさえ取れたら、異常時の処理を組み込むだけのところまで来てるので、
今から作り替えるのもなぁと思いつつ質問してみました(^^;
あとは、これが解決できたら他にも標準入出力でやり取りしないといけない処理が出てきたときに役立つだろうと。
> 標準エラーさえ取れたら、異常時の処理を組み込むだけのところまで来てるので、
> 今から作り替えるのもなぁと思いつつ質問してみました(^^;
> あとは、これが解決できたら他にも標準入出力でやり取りしないといけない処理が出てきたときに役立つだろうと。

  標準エラーを標準出力にリダイレクトできますが・・・

  Arguments = "-2"
  を
  Arguments = "-2 2>&1"

  にして実行してみて下さい。

※ 因みに、実験してみてチャント取れてます。
  尚、こまごまとコードは修正しています。
  掲載されているコードでは、少々問題あろうかと
  思ってます・・・

  全角文字出力は無いですよね?
  あった場合、Dim c As Char = Chr(reader.Read())
  では、異常な処理になる場合があります。
  reader.Read() は、Integerで返ってきます。
  要は全角1文字分のコードが入っているので・・・

以上。
確認ありがとうございます。

>>Arguments = "-2 2>&1"
にしてみたのですが、今度は何も返ってこない状態になってしまいました。
たぶん細々と修正して頂いたところに問題があるのでしょう。
もうちょっと悩んでみます。

>   全角文字出力は無いですよね?
>   あった場合、Dim c As Char = Chr(reader.Read())
>   では、異常な処理になる場合があります。
>   reader.Read() は、Integerで返ってきます。
>   要は全角1文字分のコードが入っているので・・・
ご指摘ありがとうございます。
今のところ全角文字を使う予定はありませんが、修正しておきます。

ありがとうございました。
解決済み!
2009/06/29(Mon) 21:52:12 編集(投稿者)

リダイレクトの実験は・・・

http://support.microsoft.com/kb/110930/ja

        Dim psi As ProcessStartInfo
        psi = New ProcessStartInfo
        With psi
            .FileName = "cmd.exe"
            .Arguments = "/c dir"
            .RedirectStandardInput = True
            .RedirectStandardOutput = True
            .RedirectStandardError = True
            .UseShellExecute = False
            .CreateNoWindow = True
        End With

  という風にして・・・

            .Arguments = "/c dir"
            .Arguments = "/c dir c: 1>&2 2>null"
            .Arguments = "/c dir c: 1>null 2>&1"

  のように変化させてみて、その結果の差異から判断されては?

  PSFTPが本当にどこに出力しているのか、解るかと・・・

以上。参考まで

DOBON.NET | プログラミング道 | プログラミング掲示板