Before I go on, a bit of background. We were initially using the in-built variation tools to copy content from a source language site to a number of target English sites--in other words, www.westernaustralia.com/en was being copied to the /uk, /au, /nz, and /sg sites. I won't bore you with the details but the variation tool was deemed too blunt for our requirements and one of the developers on my team wrote a custom variation tool to do exactly what we want. The custom variation tool copies sub sites and pages but unfortunately it doesn't copy documents in document libraries; we don't make extensive use of the Documents library you get when you create a new publishing site but a few speicific sites do contain PDFs that need to be pulled over.
Since a document library is a list at heart, I started by examining the SPList API, assuming it would provide me with everything I need to manage the list items. I also looked into the SPListItemCollection returned by the Items property of SPList, and the SPListItem class. SPList was pretty hopeless. SPListItemCollection was somewhat more helpful, exposing the standard Add, Delete, and Count methods, and SPListItem was really enticing with its CopyFrom and CopyTo methods. Of course this was nearly a complete waste of time as few of these methods and properties really helped out at all. CopyFrom and CopyTo failed at runtime, Delete works as advertised but SPListItemCollection does not overload the Delete method or provide a sister method to delete everything in the list, and Add only adds a new list item if you get the very confusing url parameter pointing at the right location (a quick hint: it's expecting the URL of the destination file in the case of a document library...).
When it was all said and done, I'd written my own ClearList helper method, cast my destination list to a SPDocumentLibrary, accessed the Files collection via the RootFolder property of said document library, and passed in the byte array representing the uploaded file.
Here's the code I ended up with to copy the contents of the Documents list in one sub site to the Documents list in another sub site within the same web application:
using (SPSite site = new SPSite ("http://dev-moss-mh:101/"))
{
using (SPWeb sourceWeb = site.AllWebs ["Source_Site"])
{
using (SPWeb destinationWeb = site.AllWebs ["Destination_Site"])
{
SPList sourceDocuments = sourceWeb.Lists ["Documents"];
SPList destinationDocuments = destinationWeb.Lists ["Documents"];
if (sourceDocuments.ItemCount > 0)
{
ClearList (destinationDocuments);
foreach (SPListItem currentSourceDocument in sourceDocuments.Items)
{
Console.WriteLine ("Adding: {0}", currentSourceDocument.Name);
byte [] fileBytes = currentSourceDocument.File.OpenBinary ();
const bool OverwriteDestinationFile = true;
string relativeDestinationUrl =
destinationDocuments.RootFolder.Url +
"/" +
currentSourceDocument.File.Name;
SPFile destinationFile =
((SPDocumentLibrary) destinationDocuments).RootFolder.Files.Add (
relativeDestinationUrl,
fileBytes,
OverwriteDestinationFile);
}
} } } }
As you can tell by the variable name, the Add method requires a relative URL pointing within the context of the destination site. This seems odd to me since Add ( ) is called on the destination list itself--why it can't figure out the destination URL is beyond me.
My ClearList implementation is also mildly interesting: deleting items within a foreach loop is obviously a no-no since the foreach syntax in C# is interacting with an IEnumerator object so my first attempt was to iterate over the list using a for loop and deleting list items from the zero index through to the final item in the list. This worked but only sporadically, occasionally leaving items behind. Calling ClearList a second time did the trick with a small list but that's just weird programming.
The solution I arrived at is detailed below and essentially comes down to the fact that the SharePoint list API must maintain a real-time (or part-time) connection with the database; in other words, deleting an item at index zero could mean SharePoint re-fetches the list content so by the time my for loop moves on to the next index, the list has effectively shuffled itself down so index zero is still populated. As you can see, I'm now simply iterating over the list and always deleting the item at index zero. I could have possibly used a while loop and the listToClear.Items.Count property directly but it's difficult to know whether SharePoint can be trusted in a case like this. I'll leave that up to you to try out...
private static void ClearList (SPList listToClear)
{
int initialItemCount = listToClear.Items.Count;
for (int counter = 0; counter < initialItemCount; counter++)
{
// Always delete the list item at index 0
SPListItem listItemToClear = listToClear.Items [0];
listItemToClear.Delete ();
}
listToClear.Update ();
}

This site is just a little bit of my handiwork here at Tourism Western Australia...