It's not writing because the "return" command will halt any further processing - it cannot get to the /write in any case.
Here's the same code with the write command at the right position (a match on a line read) and some cosmetic changes that make it more easy to read - your code (using a lot of pipes and weird bracket positions) is hard to read > debug. Instead of "return", "break" is used (breaks out of the loop, so commands after the loop would be processed. But as there are none, "return" would have the same effect )

Code:
on *:text:*:#:{
  if ($nick isreg #) {
  ECHO -a triggert
    var %k = 1, %kk = $lines(spam.txt) 
    while (%k <= %kk) { 
      if ($+(*,$read(spam.txt,%k),*) iswm $1-) {
        if (!$window(@Spams)) { window -mze @Spams }
        echo -t @Spams $chan $nick : $1-
        write $qt($mircdirlogs\Spams.txt) $fulldate $chan $nick : $1-
        break
      }
      inc %k
    }
  } 
}

And to make it work for queries too:
Code:
; location "#" was changed for "*" to match both channel- and query messages
on *:text:*:*:{
  ; if it's in a query theres no chan, so the condition was extended
  if (!$chan) || ($nick isreg $chan) {
    var %k = 1, %kk = $lines(spam.txt) 
    while (%k <= %kk) { 
      if ($+(*,$read(spam.txt,%k),*) iswm $1-) {
        if (!$window(@Spams)) { window -mze @Spams }
        ; the two $iif in the next lines will echo/write the channels name or "[query]" for private messages
        echo -t @Spams $fulldate $iif($chan,$v1,[query]) $nick : $1-
        write $qt($mircdirlogs\Spams.txt) $fulldate $iif($chan,$v1,[query]) $nick : $1-
        break
      }
      inc %k
    }
  } 
}