| using J2N; |
| using Lucene.Net.Support; |
| using System; |
| using System.Collections.Generic; |
| using System.IO; |
| using System.Runtime.CompilerServices; |
| using System.Text; |
| |
| namespace Lucene.Net.Util |
| { |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| using Directory = Lucene.Net.Store.Directory; |
| |
| /// <summary> |
| /// This class emulates the new Java 7 "Try-With-Resources" statement. |
| /// Remove once Lucene is on Java 7. |
| /// <para/> |
| /// @lucene.internal |
| /// </summary> |
| [ExceptionToClassNameConvention] |
| public static class IOUtils // LUCENENET specific - made static |
| { |
| /// <summary> |
| /// UTF-8 <see cref="Encoding"/> instance to prevent repeated |
| /// <see cref="Encoding.UTF8"/> lookups </summary> |
| [Obsolete("Use Encoding.UTF8 instead.")] |
| public static readonly Encoding CHARSET_UTF_8 = Encoding.UTF8; |
| |
| /// <summary> |
| /// UTF-8 charset string. |
| /// <para/>Where possible, use <see cref="Encoding.UTF8"/> instead, |
| /// as using the <see cref="string"/> constant may slow things down. </summary> |
| /// <seealso cref="Encoding.UTF8"/> |
| public static readonly string UTF_8 = "UTF-8"; |
| |
| /// <summary> |
| /// <para>Disposes all given <c>IDisposable</c>s, suppressing all thrown exceptions. Some of the <c>IDisposable</c>s |
| /// may be <c>null</c>, they are ignored. After everything is disposed, method either throws <paramref name="priorException"/>, |
| /// if one is supplied, or the first of suppressed exceptions, or completes normally.</para> |
| /// <para>Sample usage: |
| /// <code> |
| /// IDisposable resource1 = null, resource2 = null, resource3 = null; |
| /// ExpectedException priorE = null; |
| /// try |
| /// { |
| /// resource1 = ...; resource2 = ...; resource3 = ...; // Acquisition may throw ExpectedException |
| /// ..do..stuff.. // May throw ExpectedException |
| /// } |
| /// catch (ExpectedException e) |
| /// { |
| /// priorE = e; |
| /// } |
| /// finally |
| /// { |
| /// IOUtils.CloseWhileHandlingException(priorE, resource1, resource2, resource3); |
| /// } |
| /// </code> |
| /// </para> |
| /// </summary> |
| /// <param name="priorException"> <c>null</c> or an exception that will be rethrown after method completion. </param> |
| /// <param name="objects"> Objects to call <see cref="IDisposable.Dispose()"/> on. </param> |
| [Obsolete("Use DisposeWhileHandlingException(Exception, params IDisposable[]) instead.")] |
| public static void CloseWhileHandlingException(Exception priorException, params IDisposable[] objects) |
| { |
| DisposeWhileHandlingException(priorException, objects); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. </summary> |
| /// <seealso cref="DisposeWhileHandlingException(Exception, IDisposable[])"/> |
| [Obsolete("Use DisposeWhileHandlingException(Exception, IEnumerable<IDisposable>) instead.")] |
| public static void CloseWhileHandlingException(Exception priorException, IEnumerable<IDisposable> objects) |
| { |
| DisposeWhileHandlingException(priorException, objects); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s. Some of the |
| /// <see cref="IDisposable"/>s may be <c>null</c>; they are |
| /// ignored. After everything is closed, the method either |
| /// throws the first exception it hit while closing, or |
| /// completes normally if there were no exceptions. |
| /// </summary> |
| /// <param name="objects"> |
| /// Objects to call <see cref="IDisposable.Dispose()"/> on </param> |
| [Obsolete("Use Dispose(params IDisposable[]) instead.")] |
| public static void Close(params IDisposable[] objects) |
| { |
| Dispose(objects); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s. </summary> |
| /// <seealso cref="Dispose(IDisposable[])"/> |
| [Obsolete("Use Dispose(IEnumerable<IDisposable>) instead.")] |
| public static void Close(IEnumerable<IDisposable> objects) |
| { |
| Dispose(objects); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. |
| /// Some of the <see cref="IDisposable"/>s may be <c>null</c>, they are ignored. |
| /// </summary> |
| /// <param name="objects"> |
| /// Objects to call <see cref="IDisposable.Dispose()"/> on </param> |
| [Obsolete("Use DisposeWhileHandlingException(params IDisposable[]) instead.")] |
| public static void CloseWhileHandlingException(params IDisposable[] objects) |
| { |
| DisposeWhileHandlingException(objects); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. </summary> |
| /// <seealso cref="DisposeWhileHandlingException(IEnumerable{IDisposable})"/> |
| /// <seealso cref="DisposeWhileHandlingException(IDisposable[])"/> |
| [Obsolete("Use DisposeWhileHandlingException(IEnumerable<IDisposable>) instead.")] |
| public static void CloseWhileHandlingException(IEnumerable<IDisposable> objects) |
| { |
| DisposeWhileHandlingException(objects); |
| } |
| |
| |
| // LUCENENET specific - added overloads starting with Dispose... instead of Close... |
| |
| /// <summary> |
| /// <para>Disposes all given <c>IDisposable</c>s, suppressing all thrown exceptions. Some of the <c>IDisposable</c>s |
| /// may be <c>null</c>, they are ignored. After everything is disposed, method either throws <paramref name="priorException"/>, |
| /// if one is supplied, or the first of suppressed exceptions, or completes normally.</para> |
| /// <para>Sample usage: |
| /// <code> |
| /// IDisposable resource1 = null, resource2 = null, resource3 = null; |
| /// ExpectedException priorE = null; |
| /// try |
| /// { |
| /// resource1 = ...; resource2 = ...; resource3 = ...; // Acquisition may throw ExpectedException |
| /// ..do..stuff.. // May throw ExpectedException |
| /// } |
| /// catch (ExpectedException e) |
| /// { |
| /// priorE = e; |
| /// } |
| /// finally |
| /// { |
| /// IOUtils.DisposeWhileHandlingException(priorE, resource1, resource2, resource3); |
| /// } |
| /// </code> |
| /// </para> |
| /// </summary> |
| /// <param name="priorException"> <c>null</c> or an exception that will be rethrown after method completion. </param> |
| /// <param name="objects"> Objects to call <see cref="IDisposable.Dispose()"/> on. </param> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void DisposeWhileHandlingException(Exception priorException, params IDisposable[] objects) |
| { |
| Exception th = null; |
| |
| foreach (IDisposable @object in objects) |
| { |
| try |
| { |
| if (@object != null) |
| { |
| @object.Dispose(); |
| } |
| } |
| catch (Exception t) |
| { |
| AddSuppressed(priorException ?? th, t); |
| if (th == null) |
| { |
| th = t; |
| } |
| } |
| } |
| |
| if (priorException != null) |
| { |
| throw priorException; |
| } |
| else |
| { |
| ReThrow(th); |
| } |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. </summary> |
| /// <seealso cref="DisposeWhileHandlingException(Exception, IDisposable[])"/> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void DisposeWhileHandlingException(Exception priorException, IEnumerable<IDisposable> objects) |
| { |
| Exception th = null; |
| |
| foreach (IDisposable @object in objects) |
| { |
| try |
| { |
| if (@object != null) |
| { |
| @object.Dispose(); |
| } |
| } |
| catch (Exception t) |
| { |
| AddSuppressed(priorException ?? th, t); |
| if (th == null) |
| { |
| th = t; |
| } |
| } |
| } |
| |
| if (priorException != null) |
| { |
| throw priorException; |
| } |
| else |
| { |
| ReThrow(th); |
| } |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s. Some of the |
| /// <see cref="IDisposable"/>s may be <c>null</c>; they are |
| /// ignored. After everything is closed, the method either |
| /// throws the first exception it hit while closing, or |
| /// completes normally if there were no exceptions. |
| /// </summary> |
| /// <param name="objects"> |
| /// Objects to call <see cref="IDisposable.Dispose()"/> on </param> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void Dispose(params IDisposable[] objects) |
| { |
| Exception th = null; |
| |
| foreach (IDisposable @object in objects) |
| { |
| try |
| { |
| if (@object != null) |
| { |
| @object.Dispose(); |
| } |
| } |
| catch (Exception t) |
| { |
| AddSuppressed(th, t); |
| if (th == null) |
| { |
| th = t; |
| } |
| } |
| } |
| |
| ReThrow(th); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s. </summary> |
| /// <seealso cref="Dispose(IDisposable[])"/> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void Dispose(IEnumerable<IDisposable> objects) |
| { |
| Exception th = null; |
| |
| foreach (IDisposable @object in objects) |
| { |
| try |
| { |
| if (@object != null) |
| { |
| @object.Dispose(); |
| } |
| } |
| catch (Exception t) |
| { |
| AddSuppressed(th, t); |
| if (th == null) |
| { |
| th = t; |
| } |
| } |
| } |
| |
| ReThrow(th); |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. |
| /// Some of the <see cref="IDisposable"/>s may be <c>null</c>, they are ignored. |
| /// </summary> |
| /// <param name="objects"> |
| /// Objects to call <see cref="IDisposable.Dispose()"/> on </param> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void DisposeWhileHandlingException(params IDisposable[] objects) |
| { |
| foreach (var o in objects) |
| { |
| try |
| { |
| if (o != null) |
| { |
| o.Dispose(); |
| } |
| } |
| catch (Exception) |
| { |
| //eat it |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Disposes all given <see cref="IDisposable"/>s, suppressing all thrown exceptions. </summary> |
| /// <seealso cref="DisposeWhileHandlingException(IDisposable[])"/> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static void DisposeWhileHandlingException(IEnumerable<IDisposable> objects) |
| { |
| foreach (IDisposable @object in objects) |
| { |
| try |
| { |
| if (@object != null) |
| { |
| @object.Dispose(); |
| } |
| } |
| catch (Exception) |
| { |
| //eat it |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Since there's no C# equivalent of Java's Exception.AddSuppressed, we add the |
| /// suppressed exceptions to a data field via the |
| /// <see cref="ExceptionExtensions.AddSuppressed(Exception, Exception)"/> method. |
| /// <para/> |
| /// The exceptions can be retrieved by calling <see cref="ExceptionExtensions.GetSuppressed(Exception)"/> |
| /// or <see cref="ExceptionExtensions.GetSuppressedAsList(Exception)"/>. |
| /// </summary> |
| /// <param name="exception"> this exception should get the suppressed one added </param> |
| /// <param name="suppressed"> the suppressed exception </param> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| private static void AddSuppressed(Exception exception, Exception suppressed) |
| { |
| if (exception != null && suppressed != null) |
| { |
| exception.AddSuppressed(suppressed); |
| } |
| } |
| |
| /// <summary> |
| /// Wrapping the given <see cref="Stream"/> in a reader using a <see cref="Encoding"/>. |
| /// Unlike Java's defaults this reader will throw an exception if your it detects |
| /// the read charset doesn't match the expected <see cref="Encoding"/>. |
| /// <para/> |
| /// Decoding readers are useful to load configuration files, stopword lists or synonym files |
| /// to detect character set problems. However, its not recommended to use as a common purpose |
| /// reader. |
| /// </summary> |
| /// <param name="stream"> The stream to wrap in a reader </param> |
| /// <param name="charSet"> The expected charset </param> |
| /// <returns> A wrapping reader </returns> |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| public static TextReader GetDecodingReader(Stream stream, Encoding charSet) |
| { |
| return new StreamReader(stream, charSet); |
| } |
| |
| /// <summary> |
| /// Opens a <see cref="TextReader"/> for the given <see cref="FileInfo"/> using a <see cref="Encoding"/>. |
| /// Unlike Java's defaults this reader will throw an exception if your it detects |
| /// the read charset doesn't match the expected <see cref="Encoding"/>. |
| /// <para/> |
| /// Decoding readers are useful to load configuration files, stopword lists or synonym files |
| /// to detect character set problems. However, its not recommended to use as a common purpose |
| /// reader. </summary> |
| /// <param name="file"> The file to open a reader on </param> |
| /// <param name="charSet"> The expected charset </param> |
| /// <returns> A reader to read the given file </returns> |
| public static TextReader GetDecodingReader(FileInfo file, Encoding charSet) |
| { |
| FileStream stream = null; |
| bool success = false; |
| try |
| { |
| stream = file.OpenRead(); |
| TextReader reader = GetDecodingReader(stream, charSet); |
| success = true; |
| return reader; |
| } |
| finally |
| { |
| if (!success) |
| { |
| IOUtils.Dispose(stream); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Opens a <see cref="TextReader"/> for the given resource using a <see cref="Encoding"/>. |
| /// Unlike Java's defaults this reader will throw an exception if your it detects |
| /// the read charset doesn't match the expected <see cref="Encoding"/>. |
| /// <para/> |
| /// Decoding readers are useful to load configuration files, stopword lists or synonym files |
| /// to detect character set problems. However, its not recommended to use as a common purpose |
| /// reader. </summary> |
| /// <param name="clazz"> The class used to locate the resource </param> |
| /// <param name="resource"> The resource name to load </param> |
| /// <param name="charSet"> The expected charset </param> |
| /// <returns> A reader to read the given file </returns> |
| public static TextReader GetDecodingReader(Type clazz, string resource, Encoding charSet) |
| { |
| Stream stream = null; |
| bool success = false; |
| try |
| { |
| stream = clazz.FindAndGetManifestResourceStream(resource); |
| TextReader reader = GetDecodingReader(stream, charSet); |
| success = true; |
| return reader; |
| } |
| finally |
| { |
| if (!success) |
| { |
| IOUtils.Dispose(stream); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Deletes all given files, suppressing all thrown <see cref="Exception"/>s. |
| /// <para/> |
| /// Note that the files should not be <c>null</c>. |
| /// </summary> |
| public static void DeleteFilesIgnoringExceptions(Directory dir, params string[] files) |
| { |
| foreach (string name in files) |
| { |
| try |
| { |
| dir.DeleteFile(name); |
| } |
| catch (Exception) |
| { |
| // ignore |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Copy one file's contents to another file. The target will be overwritten |
| /// if it exists. The source must exist. |
| /// </summary> |
| public static void Copy(FileInfo source, FileInfo target) |
| { |
| FileStream fis = null; |
| FileStream fos = null; |
| try |
| { |
| fis = source.OpenRead(); |
| fos = target.OpenWrite(); |
| |
| byte[] buffer = new byte[1024 * 8]; |
| int len; |
| while ((len = fis.Read(buffer, 0, buffer.Length)) > 0) |
| { |
| fos.Write(buffer, 0, len); |
| } |
| } |
| finally |
| { |
| Dispose(fis, fos); |
| } |
| } |
| |
| /// <summary> |
| /// Simple utilty method that takes a previously caught |
| /// <see cref="Exception"/> and rethrows either |
| /// <see cref="IOException"/> or an unchecked exception. If the |
| /// argument is <c>null</c> then this method does nothing. |
| /// </summary> |
| public static void ReThrow(Exception th) |
| { |
| if (th != null) |
| { |
| if (th is IOException) |
| { |
| throw th; |
| } |
| ReThrowUnchecked(th); |
| } |
| } |
| |
| /// <summary> |
| /// Simple utilty method that takes a previously caught |
| /// <see cref="Exception"/> and rethrows it as an unchecked exception. |
| /// If the argument is <c>null</c> then this method does nothing. |
| /// </summary> |
| public static void ReThrowUnchecked(Exception th) |
| { |
| if (th != null) |
| { |
| throw th; |
| } |
| } |
| |
| // LUCENENET specific: Fsync is pointless in .NET, since we are |
| // calling FileStream.Flush(true) before the stream is disposed |
| // which means we never need it at the point in Java where it is called. |
| // /// <summary> |
| // /// Ensure that any writes to the given file is written to the storage device that contains it. </summary> |
| // /// <param name="fileToSync"> The file to fsync </param> |
| // /// <param name="isDir"> If <c>true</c>, the given file is a directory (we open for read and ignore <see cref="IOException"/>s, |
| // /// because not all file systems and operating systems allow to fsync on a directory) </param> |
| // public static void Fsync(string fileToSync, bool isDir) |
| // { |
| // // Fsync does not appear to function properly for Windows and Linux platforms. In Lucene version |
| // // they catch this in IOException branch and return if the call is for the directory. |
| // // In Lucene.Net the exception is UnauthorizedAccessException and is not handled by |
| // // IOException block. No need to even attempt to fsync, just return if the call is for directory |
| // if (isDir) |
| // { |
| // return; |
| // } |
| |
| // var retryCount = 1; |
| // while (true) |
| // { |
| // FileStream file = null; |
| // bool success = false; |
| // try |
| // { |
| // // If the file is a directory we have to open read-only, for regular files we must open r/w for the fsync to have an effect. |
| // // See http://blog.httrack.com/blog/2013/11/15/everything-you-always-wanted-to-know-about-fsync/ |
| // file = new FileStream(fileToSync, |
| // FileMode.Open, // We shouldn't create a file when syncing. |
| // // Java version uses FileChannel which doesn't create the file if it doesn't already exist, |
| // // so there should be no reason for attempting to create it in Lucene.Net. |
| // FileAccess.Write, |
| // FileShare.ReadWrite); |
| // //FileSupport.Sync(file); |
| // file.Flush(true); |
| // success = true; |
| // } |
| //#pragma warning disable 168 |
| // catch (IOException e) |
| //#pragma warning restore 168 |
| // { |
| // if (retryCount == 5) |
| // { |
| // throw; |
| // } |
| //#if FEATURE_THREAD_INTERRUPT |
| // try |
| // { |
| //#endif |
| // // Pause 5 msec |
| // Thread.Sleep(5); |
| //#if FEATURE_THREAD_INTERRUPT |
| // } |
| // catch (ThreadInterruptedException ie) |
| // { |
| // var ex = new ThreadInterruptedException(ie.ToString(), ie); |
| // ex.AddSuppressed(e); |
| // throw ex; |
| // } |
| //#endif |
| // } |
| // finally |
| // { |
| // if (file != null) |
| // { |
| // file.Dispose(); |
| // } |
| // } |
| |
| // if (success) |
| // { |
| // return; |
| // } |
| |
| // retryCount++; |
| // } |
| // } |
| } |
| } |