我刚刚用C#编写了我的第一个程序。请解释:
如果能提供修改后的代码和一些注释,我将非常感激,这样我就可以看到问题所在,并做一些进一步的阅读来纠正我的错误。这个程序运行得很好。
using System;
using System.IO;
using System.Text.RegularExpressions;
using iTextSharp.text.pdf;
namespace pdfStamperMemory
{
class Program
{
static void Main(string[] args)
{
// searching for JS based on: http://stackoverflow.com/a/41386971/2657875
// MemoryStream based on: http://stackoverflow.com/a/23738927/2657875
byte[] bytes;
string script;
string input = Path.GetFullPath(args[0]);
string output = Path.Combine(Path.GetDirectoryName(input), Path.GetFileNameWithoutExtension(input) + "-itext.pdf");
using (var ms = new MemoryStream())
{
using (var reader = new PdfReader(input))
{
using (var stamper = new PdfStamper(reader, ms))
{
// get all page labels
string[] labels = PdfPageLabels.GetPageLabels(reader);
string[] arr = new string[labels.Length];
for (int i = 0; i < labels.Length; i++)
{
arr[i] += labels[i];
if ((arr[0].Equals("Cover")) && i >= 1)
{
arr[i] = arr[i].Remove(0, 5);
}
}
for (int i = 1; i <= reader.NumberOfPages; i++)
{
// Get a page a PDF page
PdfDictionary page = reader.GetPageN(i);
// Get all the annotations of page i
PdfArray annotsArray = page.GetAsArray(PdfName.ANNOTS);
// If page does not have annotations
if (annotsArray == null)
{
continue;
}
// For each annotation
for (int j = 0; j < annotsArray.Size; ++j)
{
// For current annotation
PdfDictionary curAnnot = annotsArray.GetAsDict(j);
// check if has JS
PdfDictionary annotAction = curAnnot.GetAsDict(PdfName.A);
if (annotAction == null)
{
Console.Write("Page {0} annotation {1}: no action\n", i, j);
}
// test if it is a JavaScript action
else if (PdfName.JAVASCRIPT.Equals(annotAction.Get(PdfName.S)))
{
PdfObject scriptObject = annotAction.GetDirectObject(PdfName.JS);
if (scriptObject == null)
{
continue;
}
if (scriptObject.IsString())
script = ((PdfString)scriptObject).ToUnicodeString();
else if (scriptObject.IsStream())
{
using (MemoryStream stream = new MemoryStream())
{
((PdfStream)scriptObject).WriteContent(stream);
script = stream.ToString();
}
}
else
{
Console.WriteLine("Page {0} annotation {1}: malformed JS entry\n", i, j);
continue;
}
if (script.Contains("if (this.hostContainer"))
{
Regex regex = new Regex(@"pp_(.*)'");
Match text2search = regex.Match(script);
if (text2search.Success)
{
//this is a page *label*, but it needs a *number*
//to use PdfAction.GotoLocalPage
string pageLabel = text2search.Groups[1].Value;
// get index of a page label
int labelIndex = Array.IndexOf(arr, pageLabel);
// replace JS with GotoLocalPage
if (labelIndex != -1)
{
// ++ because Array.IndexOf is zer0-based
labelIndex++;
PdfAction action = PdfAction.GotoLocalPage(labelIndex, new PdfDestination(PdfDestination.XYZ, 0, reader.GetPageSize(labelIndex).Height, 1.25f), stamper.Writer);
curAnnot.Put(PdfName.A, action);
}
}
}
}
}
}
stamper.SetFullCompression();
}
}
// grab the bytes before closing things out
bytes = ms.ToArray();
}
try
{
File.WriteAllBytes(output, bytes);
Console.WriteLine("Done!");
}
catch
{
Console.WriteLine("Cannot save the file!");
}
finally
{
Console.ReadKey();
}
}
}
} 发布于 2017-02-01 06:37:57
using语句正确地释放正在实现IDisposable的对象。{},尽管它们可能是可选的。currentAnnotation?这将使这一评论变得超乎寻常。byte[] bytes;,但是只在方法的底部使用它并不是最优的。现在让我们深入研究一下代码。
using (var ms = new MemoryStream()) { using (var reader = new PdfReader(input)) { using (var stamper = new PdfStamper(reader, ms)) {
使用using是非常好的,但在这种情况下,可以/应该通过堆叠这样的用法来改进它
using (var ms = new MemoryStream())
using (var reader = new PdfReader(input))
using (var stamper = new PdfStamper(reader, ms))
{ 这将为您节省两个级别的缩进,从而防止您需要水平滚动查看所有代码。
你有一个很大的方法把所有的东西都塞进去。您应该检查代码的哪些部分可以很容易地放在方法中。
举个例子
// get all page labels string[] labels = PdfPageLabels.GetPageLabels(reader); string[] arr = new string[labels.Length]; for (int i = 0; i < labels.Length; i++) { arr[i] += labels[i]; if ((arr[0].Equals("Cover")) && i >= 1) { arr[i] = arr[i].Remove(0, 5); } }
通过使用这样的方法
private static string[] GetPageLabels(PdfReader reader)
{
string[] labels = PdfPageLabels.GetPageLabels(reader);
if (!labels[0].Equals("Cover"))
{
return labels;
}
for (int i = 1; i < labels.Length; i++)
{
labels[i] = labels[i].Remove(0, 5);
}
return labels;
} 你的主要方法会变短。
一般来说,您应该使用更多和更短的方法。这将使您更容易阅读和理解代码,如果您正在寻找一个bug,它将更容易找到。
PdfDictionary annotAction = curAnnot.GetAsDict(PdfName.A); if (annotAction == null) { Console.Write("Page {0} annotation {1}: no action\n", i, j); } // test if it is a JavaScript action else if (PdfName.JAVASCRIPT.Equals(annotAction.Get(PdfName.S)))
这是个很大的拒绝。不要在if和else if之间放置注释。您或维护人员Sam将无法一眼就看到他们(如果)是属于一起的。
如果在循环中使用与Regex regex = new Regex(@"pp_(.*)'");相同的正则表达式,则应考虑使用此过载构造函数使用RegexOptions.Compiled在循环外部创建regex。
指定将正则表达式编译到程序集。这会产生更快的执行速度,但会增加启动时间。
发布于 2017-02-01 11:33:21
for (int i= 1;i <= reader.NumberOfPages;i++)
在这种情况下尝试使用常量,因为从1开始迭代的原因并不明显。
=新Regex(@"pp_(.*)'");
您应该像@Heslacher建议的那样实例化它一次,或者您可以使用静态Regex.Match方法。它会缓存表达式,所以它也会非常快。
静态匹配(String, String)方法等效于使用指定的正则表达式模式构造Regex对象并调用实例匹配(String)方法。在这种情况下,正则表达式引擎缓存正则表达式模式。
您可以通过命名组使regex更易于阅读和使用,因此
字符串pageLabel = text2search.Groups1.Value;
会变成
string pageLabel = text2search.Groups["searchString"].Value;如果您将表达式定义为
var text2SearchMatch = Regex.Match(script, @"pp_(?<searchString>.*)'");//用GotoLocalPage if (labelIndex != -1)替换JS
与其写注释(它们往往会腐烂),不如使用助手变量:
var someLabelExsits = labelIndex != -1;
if (!someLabelExsits)https://codereview.stackexchange.com/questions/154117
复制相似问题