8

2 秒ごとに Excel ファイルを読み込もうとしています。このファイルは他の RTD アプリケーションによって更新されています。

Oledb 接続でこのファイルを読み取ることができますが、2 秒ごとに読み取ろうとすると問題が発生します。10回の試行のうち、4〜5回しか読み取れず、他の試行では例外がスローされます。

接続文字列

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1"

コード

//opening connection to excel file

using (OleDbConnection connection = new OleDbConnection(constr))//constr = connection string
{
    try
    {  
        connection.Open();
        isconopen = true;
    }
    catch
    {
        dispatcherTimer2.Start();

        connection.Close();
        isconopen = false;
    }

    // If connection is ok , then query sheet  
    if (isconopen == true)
    {
        strcon = "SELECT * FROM [" + dsheet + "]";

        using (OleDbDataAdapter adapter = new OleDbDataAdapter(strcon, connection))
        {

            try
            {


                adapter.Fill(result);
                isread = true;
                adapter.Dispose();

                connection.Close();
            }
            catch 
            {

                isread = false;
                dispatcherTimer2.Start();

                adapter.Dispose();
                connection.Close();

            }

        }
     }

    //if able to retrieve data then call some other function 
    if (isread == true)
    {
        converToCSV(0);// for further processing
    }

私を助けてください、私は過去1ヶ月からこれを試しています. お願いしますお願いします助けてください

4

3 に答える 3

7

悲しいことに、OleDB ドライバーはデフォルトでファイルを排他的に開くため、他のユーザーが使用している場合は、読み取りのためだけでも開くことができません。

2 つの考慮事項:

  • 他のアプリケーションは数ミリ秒以内にファイルの処理を終了する可能性があるため、再試行することをお勧めします
  • ドライバーは常に書き込み用にロックされたファイルを開きますが (OleDB 経由で 2 回開くことはできません)、読み取り用に共有されます (コピーできるようになります)。

とは言っても、短い一時停止の後に最初に開いてみることをお勧めします。それがまだ使用されている場合(そしてそれ以上待てない場合)は、コピーを作成して開くことができます。

関数にコードがあると仮定しましょうHandlExcelFile()

void HandleExcelFile(string path)
{
    try
    {
        // Function will perform actual work
        HandleExcelFileCore(path); 
    }
    catch (Exception) // Be more specific
    {
        Thread.Sleep(100); // Arbitrary

        try
        {
            HandleExcelFileCore(path);
        }
        catch (Exception)
        {
            string tempPath = Path.GetTempFileName();
            File.Copy(path, tempPath);

            try
            {
                HandleExcelFileCore(tempPath);
            }
            finally
            {
                File.Delete(tempPath);
            }
        }
    }
}

コードは少し見にくいので、独自の関数を作成するための出発点と考えてください。

考慮事項:

  • 再試行はそれほど悪いことではなく、この種の問題を解決する一般的な方法です。たとえば、これは Windows シェルが行うことです (ネットワークではさらに正常です)。
  • アプリケーションがファイルを閉じなかった場合は、古いデータをコピー (および読み取り) できます。常に最新のデータが必要な場合は、待つしかありません。保存されていないデータが前のタイム フレーム (信号エッジがクロック エッジにあるときのデジタル電子機器のように T - 1) に属していると仮定できる場合は、それを実行して幸せに暮らしてください。

テストされていないソリューション:

私はこれを試していないので、自分で行う必要があります。実際には (私は最初は間違っていました)、(拡張プロパティを介して) 読み取り専用接続を開くことができます。これが接続のみに適用されるか、ファイル ハンドルと接続の両方に適用されるかは文書化されていません。とにかく、接続文字列を次のように変更してみましょう。

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\nids\shes.xlsm;Extended Properties="Excel 12.0 Macro;HDR=Yes;IMEX=1;ReadOnly=true"

ReadOnly=trueの最後にa を追加しただけですExtended Properties

その他の解決策:

  • 私の頭に浮かぶ唯一の代替ソリューションは... Excelファイルを手動で読み取ることです(したがって、読み取るためだけに開くことができます)。とはいえ、この場合でも、他のアプリケーションが新しいデータを書き込んでいない可能性があります (したがって、古いデータを読み取ることになります)。
  • タイマーは一切使わない。を使用するようにデザインを変更すると、FileSystemWatcher変更が通知された場合にのみファイルを読み取ることができます。
  • 該当する場合は...共有ファイルを IPC メカニズムとして使用しないでください。まあ、あなたは2番目のアプリケーションを変更できないかもしれないので、これはあなたのケースではないかもしれません.
  • OleDB を使用して Microsoft Excel ファイルを読み取らないでください。これなど、排他ロックでファイルを開かないサードパーティの無料ライブラリが多数あります。
  • ファイルから直接データを読み取らないでください。Microsoft Excel インスタンスが常に実行されている場合は、COM 相互運用機能を使用して通知を受け取ることができます。COM アドインに関するこの一般的な記事とこれを確認して、Office 相互運用機能を備えた C# アプリケーションを既存の Microsoft Excel インスタンスに接続する方法を確認してください。
于 2013-09-14T06:34:09.217 に答える
0

同様の問題がありました。以下の修正は私のために働いた

1)シートへの接続を保持しないでください。代わりに、接続読み取りデータを開き、すぐに接続を閉じます。

2) アンマネージド アプリケーションでマネージド コードを使用している場合は、(gcnew を使用して) ポインターの代わりにマネージド型のオブジェクトを使用することを検討し、スタック セマンティクスを使用して、オブジェクトがスコープ外になったときにメモリが確実にクリーンアップされるようにします。

于 2015-09-11T17:19:12.713 に答える