Skip to content

Commit 2fa44c4

Browse files
committed
Avoid unnecessary FileInfo/DirectoryInfo allocations, #832
1 parent 0521bba commit 2fa44c4

37 files changed

Lines changed: 404 additions & 169 deletions

Lucene.Net.sln.DotSettings

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
<s:Boolean x:Key="/Default/UserDictionary/Words/=Coord/@EntryIndexedValue">True</s:Boolean>
33
<s:Boolean x:Key="/Default/UserDictionary/Words/=csharpsquid/@EntryIndexedValue">True</s:Boolean>
44
<s:Boolean x:Key="/Default/UserDictionary/Words/=LUCENENET/@EntryIndexedValue">True</s:Boolean>
5+
<s:Boolean x:Key="/Default/UserDictionary/Words/=stopword/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/UserDictionary/Words/=stopwords/@EntryIndexedValue">True</s:Boolean>
57
<s:Boolean x:Key="/Default/UserDictionary/Words/=synch/@EntryIndexedValue">True</s:Boolean>
68
<s:Boolean x:Key="/Default/UserDictionary/Words/=testsettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

src/Lucene.Net.Analysis.Common/Analysis/Compound/Hyphenation/HyphenationTree.cs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,7 @@ protected virtual string UnpackValues(int k)
127127
/// <param name="filename"> the filename </param>
128128
/// <exception cref="IOException"> In case the parsing fails </exception>
129129
public virtual void LoadPatterns(string filename)
130-
{
131-
LoadPatterns(filename, Encoding.UTF8);
132-
}
130+
=> LoadPatterns(filename, Encoding.UTF8);
133131

134132
/// <summary>
135133
/// Read hyphenation patterns from an XML file.
@@ -149,9 +147,7 @@ public virtual void LoadPatterns(string filename, Encoding encoding)
149147
/// <param name="f"> a <see cref="FileInfo"/> object representing the file </param>
150148
/// <exception cref="IOException"> In case the parsing fails </exception>
151149
public virtual void LoadPatterns(FileInfo f)
152-
{
153-
LoadPatterns(f, Encoding.UTF8);
154-
}
150+
=> LoadPatterns(f.FullName, Encoding.UTF8);
155151

156152
/// <summary>
157153
/// Read hyphenation patterns from an XML file.
@@ -160,20 +156,15 @@ public virtual void LoadPatterns(FileInfo f)
160156
/// <param name="encoding">The character encoding to use</param>
161157
/// <exception cref="IOException"> In case the parsing fails </exception>
162158
public virtual void LoadPatterns(FileInfo f, Encoding encoding)
163-
{
164-
var src = new FileStream(f.FullName, FileMode.Open, FileAccess.Read);
165-
LoadPatterns(src, encoding);
166-
}
159+
=> LoadPatterns(f.FullName, encoding);
167160

168161
/// <summary>
169162
/// Read hyphenation patterns from an XML file.
170163
/// </summary>
171164
/// <param name="source"> <see cref="Stream"/> input source for the file </param>
172165
/// <exception cref="IOException"> In case the parsing fails </exception>
173166
public virtual void LoadPatterns(Stream source)
174-
{
175-
LoadPatterns(source, Encoding.UTF8);
176-
}
167+
=> LoadPatterns(source, Encoding.UTF8);
177168

178169
/// <summary>
179170
/// Read hyphenation patterns from an XML file.

src/Lucene.Net.Analysis.Common/Analysis/Compound/Hyphenation/PatternParser.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ public virtual IPatternConsumer Consumer
8080
/// <param name="path">The complete file path to be read.</param>
8181
/// <exception cref="IOException"> In case of an exception while parsing </exception>
8282
public virtual void Parse(string path)
83-
{
84-
Parse(path, Encoding.UTF8);
85-
}
83+
=> Parse(path, Encoding.UTF8);
8684

8785
/// <summary>
8886
/// Parses a hyphenation pattern file.
@@ -103,9 +101,7 @@ public virtual void Parse(string path, Encoding encoding)
103101
/// <param name="file"> a <see cref="FileInfo"/> object representing the file </param>
104102
/// <exception cref="IOException"> In case of an exception while parsing </exception>
105103
public virtual void Parse(FileInfo file)
106-
{
107-
Parse(file, Encoding.UTF8);
108-
}
104+
=> Parse(file.FullName, Encoding.UTF8);
109105

110106
/// <summary>
111107
/// Parses a hyphenation pattern file.
@@ -114,12 +110,7 @@ public virtual void Parse(FileInfo file)
114110
/// <param name="encoding">The character encoding to use</param>
115111
/// <exception cref="IOException"> In case of an exception while parsing </exception>
116112
public virtual void Parse(FileInfo file, Encoding encoding)
117-
{
118-
var xmlReaderSettings = GetXmlReaderSettings();
119-
120-
using var src = XmlReader.Create(new StreamReader(file.OpenRead(), encoding), xmlReaderSettings);
121-
Parse(src);
122-
}
113+
=> Parse(file.FullName, encoding);
123114

124115
/// <summary>
125116
/// Parses a hyphenation pattern file.

src/Lucene.Net.Analysis.Common/Analysis/Compound/HyphenationCompoundWordTokenFilter.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ public HyphenationCompoundWordTokenFilter(LuceneVersion matchVersion, TokenStrea
131131
/// <returns> An object representing the hyphenation patterns </returns>
132132
/// <exception cref="IOException"> If there is a low-level I/O error. </exception>
133133
public static HyphenationTree GetHyphenationTree(string hyphenationFilename)
134-
{
135-
return GetHyphenationTree(hyphenationFilename, Encoding.UTF8);
136-
}
134+
=> GetHyphenationTree(hyphenationFilename, Encoding.UTF8);
137135

138136
/// <summary>
139137
/// Create a hyphenator tree
@@ -143,9 +141,7 @@ public static HyphenationTree GetHyphenationTree(string hyphenationFilename)
143141
/// <returns> An object representing the hyphenation patterns </returns>
144142
/// <exception cref="IOException"> If there is a low-level I/O error. </exception>
145143
public static HyphenationTree GetHyphenationTree(string hyphenationFilename, Encoding encoding)
146-
{
147-
return GetHyphenationTree(new FileStream(hyphenationFilename, FileMode.Open, FileAccess.Read), encoding);
148-
}
144+
=> GetHyphenationTree(new FileStream(hyphenationFilename, FileMode.Open, FileAccess.Read), encoding);
149145

150146
/// <summary>
151147
/// Create a hyphenator tree
@@ -154,9 +150,7 @@ public static HyphenationTree GetHyphenationTree(string hyphenationFilename, Enc
154150
/// <returns> An object representing the hyphenation patterns </returns>
155151
/// <exception cref="IOException"> If there is a low-level I/O error. </exception>
156152
public static HyphenationTree GetHyphenationTree(FileInfo hyphenationFile)
157-
{
158-
return GetHyphenationTree(hyphenationFile, Encoding.UTF8);
159-
}
153+
=> GetHyphenationTree(hyphenationFile.FullName, Encoding.UTF8);
160154

161155
/// <summary>
162156
/// Create a hyphenator tree
@@ -166,9 +160,7 @@ public static HyphenationTree GetHyphenationTree(FileInfo hyphenationFile)
166160
/// <returns> An object representing the hyphenation patterns </returns>
167161
/// <exception cref="IOException"> If there is a low-level I/O error. </exception>
168162
public static HyphenationTree GetHyphenationTree(FileInfo hyphenationFile, Encoding encoding)
169-
{
170-
return GetHyphenationTree(new FileStream(hyphenationFile.FullName, FileMode.Open, FileAccess.Read), encoding);
171-
}
163+
=> GetHyphenationTree(hyphenationFile.FullName, encoding);
172164

173165
/// <summary>
174166
/// Create a hyphenator tree
@@ -177,9 +169,7 @@ public static HyphenationTree GetHyphenationTree(FileInfo hyphenationFile, Encod
177169
/// <returns> An object representing the hyphenation patterns </returns>
178170
/// <exception cref="IOException"> If there is a low-level I/O error. </exception>
179171
public static HyphenationTree GetHyphenationTree(Stream hyphenationSource)
180-
{
181-
return GetHyphenationTree(hyphenationSource, Encoding.UTF8);
182-
}
172+
=> GetHyphenationTree(hyphenationSource, Encoding.UTF8);
183173

184174
/// <summary>
185175
/// Create a hyphenator tree

src/Lucene.Net.Analysis.Common/Analysis/Core/StopAnalyzer.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ public StopAnalyzer(LuceneVersion matchVersion, CharArraySet stopWords)
7777
{
7878
}
7979

80+
/// <summary>
81+
/// Builds an analyzer with the stop words from the given file. </summary>
82+
/// <seealso cref="WordlistLoader.GetWordSet(TextReader, LuceneVersion)"/>
83+
/// <param name="matchVersion"> See <see cref="LuceneVersion"/> </param>
84+
/// <param name="stopwordsFileName"> File name to load stop words from </param>
85+
/// <remarks>
86+
/// LUCENENET: This overload takes a string file name to avoid allocating a <see cref="FileInfo"/> object.
87+
/// </remarks>
88+
public StopAnalyzer(LuceneVersion matchVersion, string stopwordsFileName)
89+
: this(matchVersion, LoadStopwordSet(stopwordsFileName, matchVersion))
90+
{
91+
}
92+
8093
/// <summary>
8194
/// Builds an analyzer with the stop words from the given file. </summary>
8295
/// <seealso cref="WordlistLoader.GetWordSet(TextReader, LuceneVersion)"/>

src/Lucene.Net.Analysis.Common/Analysis/Util/FilesystemResourceLoader.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Lucene version compatibility level 4.8.1
22
using System;
33
using System.IO;
4+
#nullable enable
45

56
namespace Lucene.Net.Analysis.Util
67
{
@@ -38,7 +39,7 @@ namespace Lucene.Net.Analysis.Util
3839
/// </summary>
3940
public sealed class FilesystemResourceLoader : IResourceLoader
4041
{
41-
private readonly DirectoryInfo baseDirectory;
42+
private readonly string? baseDirectory; // LUCENENET specific: changed to use string directory name instead of allocating a DirectoryInfo (#832)
4243
private readonly IResourceLoader @delegate;
4344

4445
/// <summary>
@@ -47,7 +48,7 @@ public sealed class FilesystemResourceLoader : IResourceLoader
4748
/// are delegated to context classloader.
4849
/// </summary>
4950
public FilesystemResourceLoader()
50-
: this((DirectoryInfo)null)
51+
: this((string?)null)
5152
{
5253
}
5354

@@ -57,22 +58,44 @@ public FilesystemResourceLoader()
5758
/// Files not found in file system and class lookups are delegated to context
5859
/// classloader.
5960
/// </summary>
60-
public FilesystemResourceLoader(DirectoryInfo baseDirectory)
61+
public FilesystemResourceLoader(string? baseDirectory)
6162
: this(baseDirectory, new ClasspathResourceLoader(typeof(FilesystemResourceLoader)))
6263
{
6364
}
6465

66+
/// <summary>
67+
/// Creates a resource loader that resolves resources against the given
68+
/// base directory (may be <c>null</c> to refer to CWD).
69+
/// Files not found in file system and class lookups are delegated to context
70+
/// classloader.
71+
/// </summary>
72+
public FilesystemResourceLoader(DirectoryInfo? baseDirectory)
73+
: this(baseDirectory?.FullName, new ClasspathResourceLoader(typeof(FilesystemResourceLoader)))
74+
{
75+
}
76+
77+
/// <summary>
78+
/// Creates a resource loader that resolves resources against the given
79+
/// base directory (may be <c>null</c> to refer to CWD).
80+
/// Files not found in file system and class lookups are delegated
81+
/// to the given delegate <see cref="IResourceLoader"/>.
82+
/// </summary>
83+
public FilesystemResourceLoader(DirectoryInfo? baseDirectory, IResourceLoader @delegate)
84+
: this(baseDirectory?.FullName, @delegate)
85+
{
86+
}
87+
6588
/// <summary>
6689
/// Creates a resource loader that resolves resources against the given
6790
/// base directory (may be <c>null</c> to refer to CWD).
6891
/// Files not found in file system and class lookups are delegated
6992
/// to the given delegate <see cref="IResourceLoader"/>.
7093
/// </summary>
71-
public FilesystemResourceLoader(DirectoryInfo baseDirectory, IResourceLoader @delegate)
94+
public FilesystemResourceLoader(string? baseDirectory, IResourceLoader @delegate)
7295
{
7396
// LUCENENET NOTE: If you call DirectoryInfo.Create() it doesn't set the DirectoryInfo.Exists
7497
// flag to true, so we use the Directory object to check the path explicitly.
75-
if (baseDirectory is not null && !Directory.Exists(baseDirectory.FullName))
98+
if (baseDirectory is not null && !Directory.Exists(baseDirectory))
7699
{
77100
throw new ArgumentException("baseDirectory is not a directory or is null");
78101
}
@@ -89,35 +112,35 @@ public Stream OpenResource(string resource)
89112
{
90113
try
91114
{
92-
FileInfo file = null;
115+
string? file = null; // LUCENENET specific: changed to use string file name instead of allocating a FileInfo (#832)
93116

94117
// First try absolute.
95118
if (File.Exists(resource))
96119
{
97-
file = new FileInfo(resource);
120+
file = resource;
98121
}
99122
else
100123
{
101124
// Try as a relative path
102125
var fullPath = System.IO.Path.GetFullPath(resource);
103126
if (File.Exists(fullPath))
104127
{
105-
file = new FileInfo(fullPath);
128+
file = fullPath;
106129
}
107130
else if (baseDirectory != null)
108131
{
109132
// Try to combine with the base directory
110-
string based = System.IO.Path.Combine(baseDirectory.FullName, resource);
133+
string based = System.IO.Path.Combine(baseDirectory, resource);
111134
if (File.Exists(based))
112135
{
113-
file = new FileInfo(based);
136+
file = based;
114137
}
115138
}
116139
}
117140

118141
if (file != null)
119142
{
120-
return file.OpenRead();
143+
return new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
121144
}
122145

123146
// Fallback on the inner resource loader (this could fail)

src/Lucene.Net.Analysis.Common/Analysis/Util/StopwordAnalyzerBase.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,35 @@ protected static CharArraySet LoadStopwordSet(bool ignoreCase, Type aClass, stri
104104
}
105105
}
106106

107+
/// <summary>
108+
/// Creates a <see cref="CharArraySet"/> from a file.
109+
/// </summary>
110+
/// <param name="stopwordsFileName">
111+
/// the stopwords file name to load
112+
/// </param>
113+
/// <param name="matchVersion">
114+
/// the Lucene version for cross version compatibility </param>
115+
/// <returns> a <see cref="CharArraySet"/> containing the distinct stopwords from the given
116+
/// file </returns>
117+
/// <exception cref="IOException">
118+
/// if loading the stopwords throws an <see cref="IOException"/> </exception>
119+
/// <remarks>
120+
/// LUCENENET: This overload takes a string file name to avoid allocating a <see cref="FileInfo"/> object.
121+
/// </remarks>
122+
protected static CharArraySet LoadStopwordSet(string stopwordsFileName, LuceneVersion matchVersion)
123+
{
124+
TextReader reader = null;
125+
try
126+
{
127+
reader = IOUtils.GetDecodingReader(stopwordsFileName, Encoding.UTF8);
128+
return WordlistLoader.GetWordSet(reader, matchVersion);
129+
}
130+
finally
131+
{
132+
IOUtils.Dispose(reader);
133+
}
134+
}
135+
107136
/// <summary>
108137
/// Creates a <see cref="CharArraySet"/> from a file.
109138
/// </summary>

src/Lucene.Net.Analysis.Kuromoji/Dict/BinaryDictionary.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.IO;
99
using System.Security;
10+
using Directory = System.IO.Directory;
1011

1112
namespace Lucene.Net.Analysis.Ja.Dict
1213
{
@@ -67,21 +68,21 @@ private static string LoadDataDir()
6768
// variable. If it is null or empty after this process, we need to
6869
// load the embedded files.
6970
string candidatePath = System.IO.Path.Combine(currentPath, DATA_SUBDIR);
70-
if (System.IO.Directory.Exists(candidatePath))
71+
if (Directory.Exists(candidatePath))
7172
{
7273
return candidatePath;
7374
}
7475

75-
while (new DirectoryInfo(currentPath).Parent != null)
76+
while (Directory.GetParent(currentPath) is { } parent) // LUCENENET: Reduce DirectoryInfo allocations by only getting parent once per iteration (#832)
7677
{
7778
try
7879
{
79-
candidatePath = System.IO.Path.Combine(new DirectoryInfo(currentPath).Parent.FullName, DATA_SUBDIR);
80-
if (System.IO.Directory.Exists(candidatePath))
80+
candidatePath = System.IO.Path.Combine(parent.FullName, DATA_SUBDIR);
81+
if (Directory.Exists(candidatePath))
8182
{
8283
return candidatePath;
8384
}
84-
currentPath = new DirectoryInfo(currentPath).Parent.FullName;
85+
currentPath = parent.FullName;
8586
}
8687
catch (SecurityException)
8788
{

src/Lucene.Net.Analysis.Kuromoji/Tools/TokenInfoDictionaryBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ public TokenInfoDictionaryBuilder(DictionaryBuilder.DictionaryFormat format, str
5353
public virtual TokenInfoDictionaryWriter Build(string dirname)
5454
{
5555
JCG.List<string> csvFiles = new JCG.List<string>();
56-
foreach (FileInfo file in new DirectoryInfo(dirname).EnumerateFiles("*.csv"))
56+
// LUCENENET specific: changed to use string file names instead of allocating a FileInfo (#832)
57+
foreach (string file in Directory.EnumerateFiles(dirname, "*.csv"))
5758
{
58-
csvFiles.Add(file.FullName);
59+
csvFiles.Add(file);
5960
}
6061
csvFiles.Sort(StringComparer.Ordinal);
6162
return BuildDictionary(csvFiles);

src/Lucene.Net.Analysis.SmartCn/AnalyzerProfile.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,17 @@ private static void Init()
8080
return;
8181
}
8282

83-
8483
try
8584
{
86-
while (new DirectoryInfo(currentPath).Parent != null)
85+
while (Directory.GetParent(currentPath) is { } parent) // LUCENENET: Reduce DirectoryInfo allocations by only getting parent once per iteration (#832)
8786
{
88-
candidatePath = System.IO.Path.Combine(new DirectoryInfo(currentPath).Parent.FullName, dirName);
87+
candidatePath = System.IO.Path.Combine(parent.FullName, dirName);
8988
if (Directory.Exists(candidatePath))
9089
{
9190
ANALYSIS_DATA_DIR = candidatePath;
9291
return;
9392
}
94-
currentPath = new DirectoryInfo(currentPath).Parent.FullName;
93+
currentPath = parent.FullName;
9594
}
9695
}
9796
catch (SecurityException)

0 commit comments

Comments
 (0)